home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / keyb / stfkey40.zip / STUFF40.ASM < prev    next >
Assembly Source File  |  1992-11-01  |  76KB  |  2,569 lines

  1.    PAGE 80,132
  2.    TITLE "StuffIt, Delayed keyboard stuffer. (C) Terje Mathisen 1989-92"
  3.    Subttl "Stuffkey Vers. 3.3+ enhanced by J.Geist. See below for detalis."
  4. COMMENT `
  5.    
  6.    Ver. 4.00 -  Added {IfSucc}/{IfFail} {Else} {Endif} code. Currently
  7.                 {Prompt} and {Find} can be tested for success. This
  8.                 requires setting {Timeout}, ~ tilde is short form, before 
  9.                 using said functions. If text is found before ~ expires,
  10.                 {IfSucces} will be true. Otherwise, commands after
  11.                 {Else} or {Endif} will be executed; whichever is found 
  12.                 first. No attempt is made to match If-Else-Endifs; they
  13.                 are processed as found, based on the "Success" variable.
  14.                 Note {IfSucc}={IfTrue}={IfT} and {IfFail}={IfFalse}={IfF}.
  15.    
  16.    Ver. 3.30 -  Renamed this Stuffkey to avoid conflicts with possible
  17.                 new version of Stuffit.
  18.              -  Added {Prompt}"easy prompt" that counts string length,
  19.                 adds PROMPTADD (3) and uses slop factor of PROMPTSLOP (4).
  20.                 Thus, {Prompt}'ptext' would become: 
  21.                 {Prompt}8,0,4,'ptext'. Much simpler and usually sufficient.
  22.              -  Added ~ {TimeOot} feature to allow escaping from failed 
  23.                 {Find} and {Prompt} commands. Added var. Success for these,
  24.                 next version will allow "If Success Goto" commands.
  25.              -  Modified CountDown proc. to read timer ticks, [Bios_Time], 
  26.                 as assuming an Int 08 per tick NG in Windows, DV, etc. 
  27.              -  Added '.' no. ticks to time args. i.e., +.3 delays 3 ticks.
  28.              -  Added ERROR MESSAGES - at last!
  29.              *  All modified code is marked. Routines: GetTime, CountDown,
  30.                 ScanText; (in Parser) Detime, and ErrorMsg were affected.
  31. ENDCOMMENT `               
  32.  
  33. VerNr   EQU 400h
  34. VerStr  EQU '4.00'
  35.  
  36. FALSE   EQU 0                   ;*** V 3.30 (Stuffkey) added TRUE, FALSE, 
  37. TRUE    EQU NOT FALSE           ; PROMPTADD & PROMPTSLOP EQU'S.
  38.  
  39. PROMPTADD  EQU 3                ;default "easy prompt" dx = strlen + this
  40. PROMPTSLOP EQU 4                ;default "easy prompt" slop factor.
  41. NO_ATTR    EQU 255              ;flag to skip attribute in text searches
  42.  
  43.         LOCALS                  ; Use TASM features for easier development.
  44.         NOJUMPS
  45.  
  46. TicksPrDay      EQU 1573041
  47. TicksPrHour     EQU 65543
  48. ResidualTicks   EQU TicksPrDay MOD 0ffffh       ; 201, 0c9h ticks
  49. LastHrTicks     EQU TicksPrHour - ResidualTicks
  50.  
  51. BIOS SEGMENT AT 40h
  52.         ORG 1Ah
  53. BufferHead      dw ?
  54. BufferTail      dw ?
  55. BufferStart     dw 16 dup (?)
  56. BufferEnd       LABEL word
  57.  
  58.         ORG 49h
  59. VideoMode       db ?
  60. CrtWidth        dw ?
  61.  
  62.         ORG 4Eh
  63. CurrStart       dw ?
  64. Cursor          dw ?
  65.  
  66.         ORG 6Ch
  67. BIOS_Timer      dw 2 dup (?)
  68.  
  69.         ORG 80h
  70. KbdBufferStart  dw ?
  71. KbdBufferEnd    dw ?
  72.  
  73. BIOS ENDS
  74.  
  75. BOOT SEGMENT AT 0F000h
  76.         ORG 0FFF0h
  77. RebootLocation  LABEL FAR
  78. BOOT ENDS
  79.  
  80. ; To reduce the resident size of StuffIt, the script is compressed into tokens
  81. ; using the following algorithm:
  82. ;
  83. ; 0 and 224 are used as the character part of function keys. These codes are
  84. ; always followed by a the function key scan code.
  85. ;
  86. ; 254 is an escape character, followed by a char:scan pair. This is also used
  87. ; if we need to enter Chr(254) or Chr(255)
  88. ;
  89. ; 255 is the lead-in for an extended function code. It will be followed by
  90. ; one of these codes:
  91. ;
  92. ; Codes for extended functions, i.e not normal keys:
  93.  
  94. REBOOT_CODE     = 0
  95. ATTIME_CODE     = 1
  96. DELTATIME_CODE  = 2
  97. FIND_CODE       = 3
  98. PROMPT_CODE     = 4
  99. PRTSCRN_CODE    = 5
  100. BREAK_CODE      = 6
  101.  
  102. ;*** Some codes added for Stuffkey Ver. 3.30 & up.
  103. ;*** See the extended jump table below for definitions.
  104.  
  105. ; Use 255 to signal that the following is an extended function
  106.  
  107. EXTENDED_CODE   = 255
  108.  
  109. ; Use 254 as lead-in for keys that need both char & scan.
  110.  
  111. GETWORD_CODE    = 254
  112.  
  113. ; All other codes (1-221,223-253) are presumed to be single characters to
  114. ; place in the kbd buffer. All of them will receive the same scan code (2).
  115. ; If your application cannot accept this, you must use the {c} or [c] syntax,
  116. ; where <c> is any character. This will be translated to the US std enh kbd
  117. ; char:scan pair.
  118.  
  119.  
  120. CODE SEGMENT PARA PUBLIC 'code'
  121.         ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
  122.         ORG 0
  123. PspStart label byte
  124.  
  125.         ORG 5Ch
  126. ResidentSize    dw ?
  127.  
  128. LowStart label byte                     ; Small size TSR
  129.  
  130.         ORG 80h
  131. CommandLen      db ?
  132. CommandLine     LABEL BYTE
  133.  
  134.         ORG 100h
  135. start:
  136.         jmp init
  137.  
  138. Semafor equ 'ST'                        ; Stuffit/Stuffkey
  139.  
  140. ;LowStart label byte                    ; Move this label to decrease size!
  141. HighStart label byte
  142.  
  143. MoveDown EQU HighStart - LowStart       ; Relocation factor for resident
  144.                                         ; part of StuffIt
  145.  
  146. Int2F   proc far
  147.         cmp ax,0E000h
  148.          je @@maybe
  149.  
  150. @@chain:
  151. ;       jmp [OldInt2F]
  152.         db 0EAh
  153. OldInt2F dd ?
  154.  
  155. @@maybe:
  156.         cmp dx,Semafor                  ; Be safe, insist on semafor in DX
  157.  
  158. current = $
  159.         org $-2
  160. Semafor_1 label word
  161.         org current
  162.  
  163.          jne @@chain
  164.  
  165. @@We_Are_Here:
  166.         mov al,0FFh
  167.         mov dx,cs
  168.         mov bx,VerNr
  169.  
  170.         iret
  171.  
  172. Int2F   endp
  173.  
  174.  
  175. ; Here comes the actual, INT 8, code, which will run on every timer tick to
  176. ; execute the tokenized script.
  177. ;
  178. ; To reduce the performance overhead of having StuffIt loaded, I use a dirty
  179. ; trick: Self-modifying code.
  180. ;
  181. ; When the script has finished, the total overhead is reduced to just
  182. ; 3 instructions: PUSHF / CALL (FAR IMMEDIATE) OldTimer / IRET
  183.  
  184. PUSH_AX_OPCODE EQU  50h                 ; Opcode for PUSH AX, used when active
  185. IRET_OPCODE    EQU 0CFh                 ; Opcode for IRET, used when disabled
  186.  
  187. MyTimer PROC FAR
  188.         pushf
  189. ;       call [OldTimer]                 ; Call the old timer code first, to
  190.         db 09Ah                         ; do it's stuff and re-enable the HW.
  191. OldTimer dw ?,?
  192.  
  193. SelfModify label byte                   ; This will be IRET when idle
  194.         push ax                         ; PUSH AX = 50h, IRET = 0CFh
  195.  
  196. ; The [active] flag is initialized to -1. This way I can use an INC
  197. ; instruction to detect the first entry into this code. Multiple
  198. ; invocations will jump directly to the exit code, with very little
  199. ; overhead. (A total of only 7 instructions and 1 short jump.)
  200.  
  201.         inc byte ptr [cs:active-MoveDown] ;  INC from -1 to 0
  202.          jnz Already_Active
  203.  
  204.         STI
  205.         CLD
  206.  
  207.         push bx
  208.         push cx
  209.  
  210.         push dx
  211.         push si
  212.         push di
  213.         push ds
  214.         push es
  215.  
  216.         push cs
  217.         pop ds
  218.         ASSUME DS:CODE
  219.  
  220.         mov es,[BiosSeg-MoveDown]       ; I store 40h in a memory variable and
  221.         push ds                         ; load ES from it, as this saves one
  222.         push es                         ; instruction vs MOV AX,40/MOV ES,AX
  223.         ASSUME ES:BIOS
  224.  
  225.  
  226.         call word ptr [StuffMode-MoveDown]      ; State machine, call the 
  227.         pop es                                  ; current state handler.
  228.         pop ds                                  ; had to save for below...
  229.         cmp byte ptr [TimerOn-MoveDown],False   ; Ver. 3.30. If time out   
  230.         je @@NoTimer                            ; enabled, call CountDown
  231.         call word ptr [TimeoutCheck-MoveDown]   ; else return
  232. @@NoTimer:                                      
  233.         pop es
  234.         pop ds
  235.         pop di
  236.         pop si
  237.         pop dx
  238.  
  239.         pop cx
  240.         pop bx
  241.  
  242.         ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
  243.  
  244.         CLI
  245.  
  246. Already_Active:
  247.  
  248.         dec byte ptr [cs:active-MoveDown]
  249.  
  250.         pop ax
  251.         iret
  252. MyTimer ENDP
  253.  
  254.         ASSUME CS:CODE,DS:CODE,ES:BIOS
  255.  
  256. StuffFinished:
  257.         mov [SelfModify-MoveDown],IRET_OPCODE   ; Disable by self-modifying
  258.                                         ; May be re-enabled by a later
  259.                                         ; invocation of StuffIt.
  260.         ret
  261.  
  262. NextKey proc near
  263.         mov si,[StuffPtr-MoveDown]
  264. GetNext:
  265.         cmp si,[StuffEnd-MoveDown]
  266.          jae StuffFinished
  267.  
  268.         lodsb
  269.         cmp al,GETWORD_CODE
  270.          ja Extended                    ; Extended function
  271.          je @@GetBoth                   ; 254 => char, scan follows
  272.  
  273.         mov ah,2                        ; Simulate scan = 2 for normal chars
  274.         cmp al,224                      ; Character for Enh.Kbd new keys
  275.          je @@GetScan
  276.  
  277.         or al,al
  278.          jne stuff
  279.  
  280. @@GetScan:
  281.         mov ah,[si]
  282.         inc si
  283.          jmp short stuff
  284.  
  285. @@GetBoth:
  286.         lodsw
  287. Stuff:
  288.         CLI
  289.         mov di,[BufferTail]
  290.         stos word ptr [BIOS:di]
  291.         cmp di, OFFSET BufferEnd
  292.  
  293. BufferEndAddr label word
  294.  
  295.          jb @@1
  296.         mov di, OFFSET BufferStart
  297. BufferStartAddr label word
  298. @@1:
  299.         cmp di,[BufferHead]
  300.          je @@Overflow
  301.         mov [BufferTail],di
  302.         STI
  303. StuffOK:
  304.         mov [StuffPtr-MoveDown],si
  305.          jmp GetNext
  306.  
  307. @@OverFlow:
  308.         STI
  309.         ret
  310. NextKey ENDP
  311.  
  312. ExtendedTable label word
  313.   dw Reboot      - MoveDown
  314.   dw AbsTime     - MoveDown
  315.   dw DeltaTime   - MoveDown
  316.   dw StartFind   - MoveDown
  317.   dw StartPrompt - MoveDown
  318.   dw PrtScrn     - MoveDown
  319.   dw CtrlBreak   - MoveDown
  320.  
  321. ;**** These routines added for Ver. 3.30 (Stuffkey)  
  322.  
  323. SETTIMEOUT_CODE = ($ - offset ExtendedTable) SHR 1  
  324.   dw SetTimeOut  - MoveDown
  325.  
  326. ;**** These routines added for Ver. 4.00 (Stuffkey)  
  327. IFSUCCESS_CODE = ($ - offset ExtendedTable) SHR 1   
  328.   dw IfSuccess   - MoveDown
  329. IFFAIL_CODE = ($ - offset ExtendedTable) SHR 1   
  330.   dw IfFail   - MoveDown
  331. ELSE_CODE = ($ - offset ExtendedTable) SHR 1  
  332.   dw ElseSuccess - MoveDown
  333. ENDIF_CODE = ($ - offset ExtendedTable) SHR 1  
  334.   dw EndSuccess  - MoveDown
  335. STOP_CODE = ($ - offset ExtendedTable) SHR 1  
  336.   dw StopScript - MoveDown
  337.  
  338.  
  339. COMMENT `  
  340.   dw ScrollPause - MoveDown
  341. SCROLLPAUSE_CODE = ($ - offset ExtendedTable) SHR 1    
  342.   dw RepeatSet   - MoveDown
  343. REPEATSET_CODE = ($ - offset ExtendedTable) SHR 1    
  344.   dw RepeatLoop  - MoveDown
  345. REPEATLOOP_CODE = ($ - offset ExtendedTable) SHR 1    
  346.   dw StartProc   - MoveDown
  347. STARTPROC_CODE = ($ - offset ExtendedTable) SHR 1    
  348.   dw EndProc     - MoveDown
  349. ENDPROC_CODE = ($ - offset ExtendedTable) SHR 1    
  350.   dw VarPause    - MoveDown
  351. VARPAUSE_CODE = ($ - offset ExtendedTable) SHR 1    
  352.   dw FixedPause  - MoveDown
  353. FIXEDPAUSE_CODE = ($ - offset ExtendedTable) SHR 1    
  354. ENDCOMMENT `
  355. ;*** end 3.30 adds.
  356.  
  357. NrOfCodes = ($ - offset ExtendedTable) SHR 1
  358.  
  359. Extended PROC near
  360.         lodsb                           ; Get function code!
  361.         cmp al,NrOfCodes
  362.         jae StuffFinished               ; Program Error! Abort the script!
  363.  
  364.         cbw                             ; All codes are <= 127, so CBW is OK!
  365.         mov bx,ax
  366.         shl bx,1
  367.         jmp ExtendedTable[bx - MoveDown] ; Jump to function handler
  368.  
  369. Extended endp
  370.  
  371. ; **** Ver 4.00 - (Stuffkey) IfSuccess code. 
  372. ;   Tests if Success is true. (or false for IfFail code). 
  373. ;   If true, continues processing following keys/tokens.
  374. ;   If not, resumes at token following next {Else} or {Endif}, respectively.
  375. ;   No attempt is made to match If-Else-Endifs, they are dealt with as
  376. ; they are discovered. An unexpected {Else} will cause program to continue
  377. ; execution after the first {Endif} found. {Endif}'s are always skipped.
  378. ; ****
  379. IfSuccess Proc  near
  380. IfFail:                                 ; handle both If's here        
  381.         mov bl,IFSUCCESS_CODE           ; default "If" code
  382.         mov bh, [Success - MoveDown]    ; get "Success" True/False
  383.         cmp al,bl                       ; Success or Fail code?
  384.         jne @@IfF                       ; Avoid a jump for common IfSuccess
  385.         xor bh,True                     ; invert "Success" flag
  386. @@IfF:                                  
  387.         xor bh,True                     ; invert, back to True, nz, if IfSucc.
  388.         jz  @@NotSuccess
  389.         jmp GetNext
  390. ElseSuccess:                            ; pull a Terje, sorta fits..
  391.         mov bl,al                       ; save "else" code
  392. @@NotSuccess:
  393.         lodsb                           ; get next byte in buffer
  394.         cmp si,[StuffEnd-MoveDown]      ; ensure we haven't overrun buffer
  395.          jae StopScript
  396.         cmp al, EXTENDED_CODE           ; does it look like an ext. token?
  397.         jne @@NotSuccess                ; nope, loop.
  398.         mov ax, [si]                    ; else pick up next word
  399.         cmp ax, ENDIF_CODE * 256 + ENDIF_CODE
  400.         je @@double_check
  401.         cmp ax, ELSE_CODE  * 256 + ELSE_CODE
  402.         jne @@NotSuccess                ; if we get past this, have found
  403.         cmp bl, IFSUCCESS_CODE          ; {Else}; only allowed if last
  404.         jne @@NotSuccess                ; command was IfSuccess
  405. @@double_check:
  406.         cmp byte ptr [si+2], EXTENDED_CODE      ;** Improve if/else code ?
  407.         jne @@NotSuccess
  408.         lodsw
  409.         lodsb
  410.         jmp GetNext                     ; continue processing
  411. IfSuccess Endp
  412.  
  413. EndSuccess Proc near
  414.         lodsw
  415.         jmp GetNext
  416. EndSuccess endp
  417.  
  418. StopScript Proc Near
  419.         jmp StuffFinished
  420. StopScript Endp
  421.  
  422. ; **** Ver 3.30 - changed to Cold boot - better in Desqview & Windows.
  423. ; this code definitely needs help in the multitasking and disk cache 
  424. ; flushing! J.Geist 6Oct92.
  425. Reboot proc near
  426.         mov word ptr [BIOS: 72h],1234h  ; == Warm Boot (CtrlAltDel)
  427.         mov word ptr [BIOS: 72h],0      ; == Cold Boot (Reset button)
  428.         jmp RebootLocation              ; == F000:FFF0
  429. Reboot endp
  430.  
  431. PrtScrn proc near
  432.         int     5
  433.         jmp     GetNext
  434. PrtScrn endp
  435.  
  436. CtrlBreak proc near
  437.         int     1Bh
  438.         xor     ax,ax
  439.         jmp     Stuff
  440. CtrlBreak endp
  441.  
  442. AbsTime:                                ; Both Abs time & Delta time land here
  443. DeltaTime:                              ; ---- " ----
  444. SetTimeOut:                             ; Ver. 3.30 TimeOut too.
  445. ;*** Ver. 3.30 (J.G.) modified GetTime a fair bit.
  446. GetTime proc near
  447.         mov [Success-MoveDown],False
  448.         mov word ptr [TimeoutVars - MoveDown], False
  449. ;        mov [TimedOut-MoveDown],False  ; above word move takes care of
  450. ;        mov [TimerOn-MoveDown],False   ; of these two prev byte moves.
  451.         cmp al,SETTIMEOUT_CODE
  452.         jne @@NotTimer
  453.         mov [TimerOn-MoveDown], True
  454. @@NotTimer:
  455.         cmp al, ATTIME_CODE
  456.         lodsw                           ; Next 3 bytes is # of ticks
  457.         mov dl,[si]
  458.         jnz @@TimeOk                    ; Delta time, so wait # of ticks
  459.  
  460. ; Wait until time equal: Calculate remaining ticks
  461.         
  462.         sub ax,[Bios_Timer]
  463.         sbb dl,BYTE PTR [Bios_Timer+2]
  464.          jae @@TimeOk
  465.  
  466.         add ax,TicksPrDay AND 0FFFFh
  467.         adc dl,TicksPrDay Shr 16
  468.  
  469. @@TimeOK:
  470.         inc si
  471.         mov [StuffPtr-MoveDown],si      ; Point to next byte
  472.  
  473.         sub dh,dh                       ; Fill top of DX with 0
  474.         or ax,dx
  475.         jz @@WaitZero                   ; Special case, wait for empty kbd
  476.  
  477.         mov [CountLow-MoveDown],ax      ; Save # ticks to wait, low word.
  478.         mov [CountHigh-MoveDown],dl     ; and # ticks hi byte.
  479.  
  480. ;*** 3.30. Relying on Int 08 every timer tick NG in DV, Windows, etc.
  481. ;          now reading Bios_Timer, using actual elapsed ticks.        
  482.  
  483.         mov ax,[Bios_Timer]             ; Recover current low ticks.
  484.         mov [OldTicks-MoveDown],ax      ; and save.
  485.         cmp [TimerOn-MoveDown], False   ; Check if timeout desired
  486.         je @@SetCount                   ; Set up for countdown if Timer off.
  487.                                         ; else set up for next key.
  488.         mov [StuffMode-MoveDown], OFFSET NextKey - MoveDown
  489.         ret
  490. @@SetCount:        
  491.         mov [StuffMode-MoveDown], OFFSET CountDown - MoveDown
  492.         ret
  493.  
  494. @@WaitZero:
  495.         mov [TimerOn-MoveDown],False
  496.         mov [StuffMode-MoveDown], OFFSET WaitEmpty - Movedown
  497.         ret
  498. GetTime endp
  499.  
  500. CountDown proc near
  501.         mov ax, [Bios_Timer]            ; 3.30 Get current ticks
  502.         mov bx, [OldTicks-MoveDown]     ; get last tick count
  503.         mov [OldTicks-MoveDown], ax     ; update old tick count.
  504.         SUB ax, bx                      ; calc. REAL #ticks gone by.
  505.         ja @@NoLWrap                    ; low ticks wrapped if below
  506. ;** check for new day here when low count wraps
  507.         cmp [Bios_Timer+2],0            ; new day if high ticks = 0
  508.         jne @@NoLWrap                   ; adjust low ticks if so
  509.         add ax, ResidualTicks           ; we lose these ticks at day-wrap.
  510. @@NoLWrap:
  511.         SUB [CountLow-MoveDown], ax     ; Subtract elapsed ticks
  512.         ja @@NoChange                   ; If above, continue
  513.         jnz @@DecHi                     ; if non zero, dec hi count
  514.         DEC [CountLow-MoveDown]         ; special case for 0
  515. @@DecHi:         
  516.         SUB [CountHigh-MoveDown],1
  517.          jae @@NoChange
  518.         cmp [TimerOn-MoveDown], True
  519.         jne @@StartNextKey
  520.         mov [TimerOn-MoveDown], False
  521.         mov [TimedOut-MoveDown], True
  522.         ret
  523. ; **** 3.30. Admittedly Terje's coding saves bytes..but I sure don't like
  524. ;            'jumping' in & out of proc's - like WaitEmpty jumps to this
  525. ;            this label....oh well. JG.
  526. StartNextKey:
  527. @@StartNextKey:
  528.         mov [StuffMode-MoveDown], OFFSET NextKey - MoveDown
  529. @@NoChange:
  530.         ret
  531. CountDown endp
  532.  
  533. WaitEmpty proc near
  534.         mov ax,[BufferHead]
  535.         cmp ax,[BufferTail]
  536.         je StartNextKey
  537.         ret
  538. WaitEmpty endp
  539.  
  540. StartPrompt:
  541.         mov [Success-MoveDown], False
  542.         mov [StuffMode-MoveDown], offset ScanPrompt - MoveDown
  543.         mov [StuffPtr-MoveDown],si
  544.  
  545. ; si -> dx:BYTE, dy:BYTE, count:WORD, len:BYTE, attr:BYTE, st:BYTE * len
  546.  
  547. ScanPrompt:                             ; Find start posn'n
  548.  
  549.         mov si,[StuffPtr-MoveDown]
  550.  
  551.         lodsw                           ; AL = dx, AH = dy
  552.         mov cx,[Cursor]                 ; CL = X,  CH = y
  553.         sub cl,al
  554.          jae @@1
  555.         sub cl,cl
  556. @@1:
  557.         sub ch,ah
  558.          jae @@2
  559.         sub ch,ch
  560. @@2:
  561.         mov al,byte ptr [CrtWidth]
  562.         mul ch                          ; AX = Y-offset
  563.         sub ch,ch
  564.         add ax,cx
  565.         shl ax,1                        ; AX = Start of scan
  566.  
  567.          jmp short Scan1
  568.  
  569. StartFind:
  570.         mov [Success-MoveDown], False
  571.         mov [StuffMode-MoveDown], offset ScanText - MoveDown
  572.         mov [StuffPtr-MoveDown],si
  573.  
  574. ; si -> start:WORD, count:WORD, len:BYTE, attr:BYTE, st:BYTE * len
  575.  
  576. ScanText proc near
  577.  
  578.         mov si,[StuffPtr-MoveDown]
  579.         lodsw                           ; starting offset in screen
  580.  
  581. Scan1:
  582.         mov di,ax
  583.         lodsw
  584.         mov cx, ax                      ; # of char cells to search
  585.  
  586.         lodsw                           ; AL = len, AH = attr
  587.         mov dl,al
  588.         xor dh,dh                       ; Text len
  589.  
  590.         dec dx                          ; Skip first char in length
  591.  
  592.         mov bx, 0B000h
  593.         cmp [VideoMode],7
  594.          je @@1
  595.         cmp [VideoMode],3
  596.          ja @@done
  597.         mov bh,0B8h
  598. @@1:
  599.         mov es,bx                       ; ES -> video segment
  600. ASSUME ES:NOTHING
  601.  
  602.         inc si                          ; Skip first char
  603.         cmp ah,255                      ; ATTR = 255 -> no attr
  604.          je @@FindChar
  605.  
  606. @@FindCharAttr:
  607.         mov al,[si-1]                   ; First char to match
  608.   repne scasw
  609.          jne @@done
  610.         or dx,dx                        ; Remaining length = 0
  611.          jz @@found
  612.  
  613.         push cx
  614.         push si
  615.         push di
  616.         mov cx,dx
  617. @@l2:
  618.         lodsb
  619.         scasw
  620.          loope @@l2
  621.  
  622.         pop di
  623.         pop si
  624.         pop cx
  625.          je @@found                     ; Yes, all chars match!
  626.          jcxz @@done                    ; No more room!
  627.          jne @@FindCharAttr             ;  this BUG was found by rbabcock!
  628.  
  629. @@FindChar:
  630.         mov al,[si-1]
  631.         dec di
  632. @@l3:
  633.          jcxz @@done                    ; No more room to start in!
  634. @@l31:
  635.         inc di
  636.         scasb
  637.          loopne @@l31
  638.  
  639.          jne @@done
  640.  
  641.         or dx,dx
  642.          jz @@found
  643.  
  644.         push cx
  645.         push si
  646.         push di
  647.         mov cx,dx
  648. @@l4:
  649.         inc di
  650.         cmpsb
  651.          loope @@l4
  652.  
  653.         pop di
  654.         pop si
  655.         pop cx
  656.          jne @@l3
  657.  
  658. @@found:
  659.         mov [Success-MoveDown],True     ; Flag a succesful find/prompt
  660. @@FoundRet:        
  661.         mov word ptr [TimeOutVars-MoveDown], False
  662. ; ** above covers both bytes in next two commented out lines. V 3.30
  663. ;        mov [TimedOut-MoveDown], False
  664. ;        mov [TimerOn-MoveDown], False
  665.         add si,dx                       ; Point after text to search for
  666.         mov [StuffMode-MoveDown], offset NextKey - MoveDown
  667.         mov [StuffPtr-MoveDown],si
  668.         ret
  669. @@done:
  670.         cmp [TimedOut-MoveDown],True
  671.         je @@FoundRet
  672.         ret
  673. ScanText Endp
  674.  
  675.         ALIGN 2
  676.  
  677. BiosSeg         dw 40h
  678.  
  679. FirstByteToCopy label byte
  680.  
  681. StuffPtr        dw OFFSET StuffBuffer - MoveDown
  682. StuffEnd        dw ?
  683. StuffMode       dw OFFSET NextKey - MoveDown
  684. TimeOutCheck    dw OFFSET CountDown - MoveDown
  685.  
  686. TimeoutVars     label word              ; Used to access next two as word,
  687. TimerOn         db False                ; TimerOn low & TimeOut hi.
  688. TimedOut        db False                ; DO NOT REARRANGE THESE THREE!
  689.  
  690. Success         db False
  691. ScrollPause     db True
  692. CountLow        dw ?
  693. CountHigh       db ?                    ; Use 24 bits for tick counter
  694. OldTicks        dw ?
  695. active          db -1
  696.  
  697. ResidentEnd     EQU $
  698.  
  699. StuffBuffer     LABEL byte
  700.  
  701. StartMsg db 'Stuffkey ',VerStr," J.Geist's enhancements to "
  702.          db "T.Mathisen's StuffIt 3.21 (C) 1989-92."
  703.          db 13,10,'$'
  704.  
  705. UsageMsg label byte
  706. db 13,10
  707. db 'Syntax: Stuffit/Stuffkey <commands>',13,10
  708. db ' +|=|~[[hh:]mm:]ss : Delay (+), until(=), timeout in(~) a specified time.',13,10
  709. db '        or             +5 waits 5 secs. +.5 waits 5 timer ticks.,',13,10
  710. db '      +|~.nn           =14:: waits til 2pm. +0 til kbd buffer empty.',13,10
  711. db '                       ~1: will timeout next {Find}, {Prompt} in 1 min.',13,10                             
  712. db " 'TEXT'",' or "TEXT"     : Stuff all the characters in TEXT',13,10
  713. db ' {KeyName} (/L lists) : {F1}, [sF1], {^Left}, {Home}, [Reboot], {Prompt}, etc.',13,10
  714. db ' <char>[:<scan>]      : Char. code. 27=<Esc>, 13=<CR>, 43:74=<Num+>,  etc.',13,10
  715. db ' @<scan code>         : Stuff a given scan code (char=0). @68=F10,@73=PgUp etc.',13,10
  716. db ' Fx,y,n[,attr],"TEXT" : Find "TEXT" in an area starting at (X,Y),',13,10
  717. db "  (or {Find}x,y etc)     and being (N) char's long. (Top left = 1,1)",13,10
  718. db ' P[dx,dy,n[,attr],]"TEXT" : Find "TEXT", relative to (behind) cursor. ie:',13,10
  719. db '  (or {Prompt} etc)     P"ID: " = P7,0,4,"ID: " finds ID: @curs X -7 to -4.',13,10
  720. db ' {IfSucc} {Else} {Endif}  : Use with {Timeout} {Prompt} & {Find}. See docs!',13,10
  721. db '-------------------- Command Line Startup Options ----------------------',13,10
  722. db ' /F:File  : Read cmds from <File>.   /L    : List mnemonic key names.',13,10
  723. db ' /B:nnn   : Buffer size. 512 def.    /Sab  : "ab" vs."ST" signature. ',13,10
  724. db ' /R       : Remove pgm from RAM.     /E    : Expanded kbd ptrs 40:80, 82',13,10
  725. ;** add /Q quit in next ver! 4.01?  
  726. ; db ' /Q       : Quiet mode, except errs.',13,10
  727. db '$'
  728.  
  729.  
  730. ;************************************************************************
  731. ;            Error messages - added in Stuffkey 3.30 - J. Geist
  732. ;*************************************************************************
  733. LinErrMsg db '** Error lin# $'
  734.  
  735. EndStrMsg label byte
  736. CRLF db 13,10,'$'
  737.  
  738. UpdateMsg       db 'Resident copy updated!',13,10,'$'
  739.  
  740. StayResMsg      db 'Resident code loaded!',13,10,'$'
  741.  
  742. RemovedMsg      db 'Resident code removed from RAM!',13,10,'$'
  743.  
  744. WrongVerMsg db 'A different version of StuffIt/Stuffkey is already resident!'
  745.             db 13,10,'$'
  746.  
  747. NotRemovedMsg  label byte
  748.  db 'Resident code cannot be removed, as another '
  749.  db   'program is using the',13,10
  750.  db 'Timer (Int 8) and/or the Multiplex (Int 2F) '
  751.  db   'vector. Please remove all',13,10
  752.  db 'programs loaded after StuffIt/Stuffkey, '
  753.  db   'and retry the operation.',13,10,'$'
  754.  
  755. RamErrMsg label byte
  756.  db 'Not enough RAM! (Need at least 128 kB to initialize program.)',13,10,'$'
  757.  
  758. FileErrMsg label byte
  759.  db 'Error reading input file!',13,10,'$'
  760.  
  761. ResidentToSmallMsg label byte
  762.  db 'Resident buffer to small! Try to remove it (/R) and reload.',13,10,'$'
  763.  
  764. ;*** Error_msg's added in Stuffkey v3.30 - J.Geist
  765. InvalidMsg      db ' Invalid ','$'
  766. ExtraErrMsg     db ' Bad ','$'
  767. BadTokenMsg     db 'Token. ','$'
  768. BadTimeMsg      db 'Time. ','$'
  769. BadFindMsg      db 'Find string cmd. ','$' 
  770. BadPromptMsg    db 'Prompt find cmd. ','$'
  771. BadParmMsg      db 'or missing parameter(s). ','$'
  772. BadStringMsg    db 'String or closing quote(s). ','$'
  773. BadNumMsg       db 'number. ','$'
  774. BadRangeMsg     db 'number - out of range. ','$'
  775. RemNresErrMsg   db '/R removal requested - program is NOT resident. ','$'
  776. BadCmdOptMsg    db 'Command line options. ','$'
  777. UndefErrMsg     db 'or unknown command. ','$'
  778. ;*** end of added error msgs in v3.30
  779.  
  780. ;FirstBlock      dw ?
  781. ;SecondBlock     dw ?
  782.  
  783.         JUMPS        ; Allow inefficient code in transient part of code!
  784.                      ; This makes it more readable.
  785.  
  786. Init proc near
  787. ASSUME DS:CODE, ES:CODE
  788.  
  789.         mov     ax,OFFSET StuffBuffer - MoveDown + 512 + 15
  790.         and     ax,0FFF0h
  791.         mov     [ResidentSize], ax
  792.  
  793. ; Start by relocating the program into a second segment
  794.  
  795. ;        mov     [FirstBlock],CS         ; Save segment addr
  796.  
  797.         mov     ah,4Ah
  798.         mov     bx,2000h                ; Realloc to 128 kB
  799. ;       mov     es,[FirstBlock]
  800.         int     21h
  801.         mov     dx, offset RamErrMsg
  802.          jc     ErrorMessage
  803.  
  804. ;        mov     ah,48h
  805. ;        mov     bx,1000h
  806. ;        int     21h                     ; Alloc second 64kB block
  807. ;        mov     dx, offset RamErrMsg
  808. ;         jc     ErrorMessage
  809.  
  810.         mov     ax,cs
  811.         add     ax,1000h                ; Point after 1st 64kB
  812.  
  813.         mov     es,ax
  814. ;        mov     [SecondBlock],es
  815.         sub     si,si
  816.         mov     di,si
  817.         mov     cx,(OFFSET ProgramEnd - OFFSET PspStart + 1) Shr 1
  818.         cld
  819.         rep     movsw
  820.  
  821.         push    es
  822.         mov     ax, OFFSET Continue
  823.         push    ax
  824.         retf
  825.  
  826. ;        pop     cs                      ; Jump into second copy of program!
  827. Continue:
  828.         push    ds
  829.         push    cs
  830.         pop     ds
  831.         pop     es                      ; DS=CS = SecondBlock, ES=FirstBlock
  832.  
  833. ; Move resident part of code as low as possible:
  834.  
  835.         mov     si, OFFSET HighStart
  836.         mov     di, OFFSET LowStart
  837.         mov     cx, OFFSET ResidentEnd - OFFSET HighStart
  838.         rep     movsb
  839.  
  840.         mov dx, OFFSET StartMsg
  841.         mov ah,9
  842.         int 21h
  843.         mov ax, OFFSET UndefErrMsg      ; Init error msg as undefined.
  844.         mov SynErrMsg,ax
  845.         call Parse
  846.  
  847.         cmp di, OFFSET StuffBuffer - MoveDown
  848.         mov dx, offset UsageMsg
  849.          je ErrorMessage                ; No parameters!
  850.  
  851.         push    es
  852.         pop     ds                      ; DS,ES,SS = FirstBlock
  853.  
  854.         mov [StuffEnd-MoveDown],di
  855. ;       mov [StuffMode-MoveDown], OFFSET NextKey - MoveDown
  856. ;       mov [StuffPtr-MoveDown], OFFSET StuffBuffer - MoveDown
  857.  
  858. ;       mov [active-MoveDown],-1                 ; Initialize [active] flag
  859. ;       mov [BiosSeg-MoveDown],40h               ; Fast load of ES: when resident
  860.  
  861.         call TestSecond                 ; Don't return if second copy!
  862.  
  863. ; Get old int 2F interrupt
  864.  
  865.         mov ax,352Fh
  866.         int 21h
  867.         mov WORD PTR [OldInt2F-MoveDown],BX
  868.         mov WORD PTR [OldInt2F+2-MoveDown],ES
  869.  
  870. ; Get old timer interrupt
  871.         mov ax,3508h
  872.         int 21h
  873.         mov WORD PTR [OldTimer-MoveDown],BX
  874.         mov Word Ptr [OldTimer+2-Movedown],ES
  875.  
  876. ; Enter our routine first
  877.  
  878.         mov ax,252Fh
  879.         mov dx, OFFSET Int2F - MoveDown
  880.         int 21h
  881.  
  882.         mov ax,2508h
  883.         mov dx, OFFSET MyTimer - MoveDown
  884.         int 21h
  885.  
  886.         mov ES, [DS:2Ch]
  887.         mov ah,49h
  888.         int 21h
  889.         mov word ptr [DS:2Ch],0         ; Signal no environment!
  890.  
  891.         push ds
  892.         push cs
  893.         pop ds
  894.         mov dx, OFFSET StayResMsg
  895.         mov ah,9
  896.         int 21h
  897.         pop ds
  898.  
  899.         mov cx,5
  900. @@CloseLoop:
  901.         mov bx,cx
  902.         dec bx
  903.         mov ah,3Eh
  904.         int 21h
  905.          loop @@CloseLoop
  906.  
  907.         push ss
  908.         pop ds
  909.         mov dx, [DS:ResidentSize]
  910.         cmp dx, [DS:Stuffend-MoveDown]
  911.          ja @@OK
  912.         mov dx, [DS:StuffEnd-MoveDown] ; DX = MAX(ResidentSize, StuffEnd)
  913.         mov [DS:ResidentSize],dx
  914. @@OK:
  915.         add dx,15
  916.         mov cl,4
  917.         shr dx,cl
  918.         mov ax,3100h
  919.         int 21h                         ; Go TSR with first block
  920.  
  921. Init Endp
  922.  
  923. FindFirst proc near
  924.  
  925.         mov dx,Semafor
  926. current = $
  927.         org $-2
  928. Semafor_2 label word
  929.         org current
  930.  
  931.         mov ax,0E000h
  932.         xor bx,bx
  933.         int 2Fh
  934.  
  935.         cmp al,0FFh
  936.          jne @@done
  937.  
  938.         cmp bx, VerNr
  939.          je @@done
  940.  
  941.         mov dx, offset WrongVerMsg
  942.          jmp ErrorMessage
  943.  
  944. @@done:
  945.         ret                             ; Return ZERO if found
  946.  
  947. FindFirst endp
  948.  
  949. TestSecond proc near
  950.         call FindFirst
  951.          jne @@NotFound
  952.  
  953.         mov es,dx                       ; Save segment
  954.  
  955. ; This is the second copy! ES -> to first copy
  956. ; Test if enough room in resident program:
  957.  
  958.         mov ax,[StuffEnd-MoveDown]
  959.         cmp ax,[ES:ResidentSize]
  960.         mov dx, OFFSET ResidentToSmallMsg
  961.          ja ErrorMessage
  962.  
  963. ; Will now move all data into first copy, including pointers and StuffMode
  964.  
  965.         mov [ES:SelfModify-MoveDown], IRET_OPCODE ; Stop resident program
  966.         mov [DS:SelfModify-MoveDown], IRET_OPCODE ; Stop this version!
  967.  
  968.         mov si, offset FirstByteToCopy - MoveDown
  969.         mov di, si
  970.         mov cx, ax                      ; [StuffEnd]
  971.         sub cx,si
  972.         rep movsb
  973.  
  974.         mov [ES:SelfModify-MoveDown], PUSH_AX_OPCODE ; Restart resident version
  975.  
  976.         mov dx, OFFSET UpdateMsg
  977.         mov ah,9
  978.         int 21h
  979.  
  980.         mov ax,4C00h
  981.         int 21h
  982.  
  983. @@NotFound:
  984. ParseFinish:
  985.         ret
  986.  
  987. TestSecond ENDP
  988.  
  989. LocalSyntax:
  990.         jmp Syntax
  991.  
  992. EOF     EQU 26
  993. LF      EQU 10                  ; Use LineFeed to count lines
  994.  
  995. LineNr          dw      ?
  996. StartLineDW    Label Dword      ; Ver 3.30. Holds ptr to beg. of parsed line    
  997. StartLine       dw      ?       ; Offset of above...do not move!
  998. StartLineSeg    dw      ?       ; SEGment of above...not sure if need this...
  999. StartItem       dw      ?       ; ptr to beg of parsed item
  1000. ErrLoc          dw      ?       ; ptr to loc where parser gave up
  1001. SynErrMsg       dw      ?       ; ptr to appropriate error message.
  1002. BadNum          db      False   ; flag for bad number
  1003. BadRange        db      False   ; flag for bad numeric range
  1004. BadParm         db      False   ; flag for bad or missing params
  1005. BadString       db      False   ; flag for bad string - as a param usually.
  1006.  
  1007. Parse Proc near
  1008.         cld
  1009.         mov si, OFFSET CommandLine
  1010.  
  1011.         mov bl,[si-1]
  1012.         sub bh,bh
  1013.         mov word ptr [si+bx],13 + (EOF * 256) ; EOF is ending marker
  1014.  
  1015. RestartParse:
  1016.         mov di, OFFSET StuffBuffer - MoveDown
  1017.  
  1018.         mov     [LineNr],0
  1019. NewLine:
  1020.         inc     [LineNr]
  1021.         mov     StartLine, si
  1022. ParseNextChar:
  1023.         mov     StartItem, si
  1024.         mov     ErrLoc, si
  1025.         mov     SynErrMsg, OFFSET UndefErrMsg
  1026.         lodsb
  1027.  
  1028.         cmp al,EOF
  1029.          je ParseFinish
  1030.  
  1031.         cmp     al,LF
  1032.          je     NewLine                 ; LF marks the end of one line
  1033.  
  1034.         cmp     al,';'                  ; ';' makes the rest of the line a
  1035.          je     @@Comment               ; comment
  1036.  
  1037.         cmp     al,' '
  1038.          jbe    ParseNextChar
  1039.  
  1040.         cmp al,'0'
  1041.          jb @@NotDigit
  1042.         cmp al,'9'
  1043.          ja @@NotDigit
  1044. @@Digit:
  1045.         dec si
  1046.         mov bx,255
  1047.         call GetNumber
  1048.         cmp al,':'
  1049.         mov al,bl
  1050.         mov ah,2
  1051.          jne @@NotTwo
  1052.  
  1053.         push ax
  1054.         mov bx,255
  1055.         call GetNumber
  1056.         cmp al,':'
  1057.          je LocalSyntax
  1058.  
  1059.         pop ax
  1060.         mov ah,bl
  1061.  
  1062. @@NotTwo:
  1063.         Call SaveChar
  1064.          jmp ParseNextChar
  1065.  
  1066. @@Comment:
  1067.         lodsb
  1068.  
  1069.         cmp     al,EOF
  1070.          je     ParseFinish
  1071.  
  1072.         cmp     al,13
  1073.          je     ParseNextChar
  1074.  
  1075.         cmp     al,LF
  1076.          jne    @@Comment
  1077.  
  1078.         jmp     NewLine
  1079.  
  1080. @@NotDigit:
  1081.         cmp al,'/'
  1082.          je ParseOption
  1083.         cmp al,'-'
  1084.          je ParseOption
  1085.  
  1086.         cmp al,'@'
  1087.         jne @@NotFunc
  1088.         mov bx,255
  1089.         call GetNumber
  1090.         mov ah,bl
  1091.         xor al,al
  1092.         stosw
  1093.          jmp ParseNextChar
  1094.  
  1095. @@NotFunc:
  1096.         cmp al,"'"
  1097.          je @@Quote
  1098.         cmp al,'"'
  1099.          jne @@NotQuote
  1100. @@Quote:
  1101.         mov bl,al                       ; Save starting quote char
  1102.         mov StartItem, si               ; 3.30 save ptr to item in our seg.
  1103. @@2:
  1104.         lodsb
  1105.         cmp al,13                       ; Missing last quote
  1106.          je @@MisQuote                  ; Flag the error
  1107.         cmp al,bl                       ; Ending quote?
  1108.          je ParseNextChar               ; Yes, restart
  1109.         mov ah,2                        ; Assume scan = 2
  1110.         call SaveChar
  1111.          jmp @@2
  1112. @@MisQuote:                             ; Ver 3.30 added error msgs.
  1113.         mov SynErrMsg, OFFSET BadStringMsg
  1114.         mov ErrLoc, si
  1115.         jmp Syntax
  1116. @@NotQuote:
  1117.         cmp al,'~'
  1118.          jne @@2_5
  1119.          jmp TimeOut
  1120. @@2_5:        
  1121.         cmp al,'+'
  1122.          jne @@3
  1123.          jmp DeTime
  1124. @@3:
  1125.         cmp al,'='
  1126.          jne @@4
  1127.          jmp AtTime
  1128.  
  1129. @@4:
  1130. ; Use ! to signal Reboot
  1131.         cmp al,'!'
  1132.          je SignalReboot
  1133.  
  1134.         cmp al,'f'
  1135.          je FindNear
  1136.         cmp al,'F'
  1137.          je FindNear
  1138.  
  1139.         cmp al,'p'
  1140.          je PromptNear
  1141.         cmp al,'P'
  1142.          je PromptNear
  1143.  
  1144.         cmp  al,'{'                     ; Start of token!
  1145.          je  StartToken
  1146.         cmp  al,'['                     ; Start of token!
  1147.          je  StartToken
  1148.  
  1149. ; Fall into syntax error!
  1150.         mov SynErrMsg, OFFSET UndefErrMsg
  1151.         mov ErrLoc, si
  1152. Parse endp
  1153. ; ******************************************************************
  1154. ; Syntax error handling. Much modified in Stuffkey 4.00. Now points
  1155. ; to Startitem and Errloc with ^---^, if possible.
  1156. ; 1Nov92 J.Geist
  1157. ; *******************************************************************
  1158. Syntax Proc near
  1159.         push    cs
  1160.         pop     ds
  1161.  
  1162.         mov     dx, OFFSET UsageMsg             ; display usage help
  1163.         mov     ah,9
  1164.         int     21h
  1165.         
  1166.         mov     dx, OFFSET EndStrMsg            ; CRLF
  1167.         mov     ah,9
  1168.         int     21h
  1169.  
  1170. ;        lds     si, StartLineDW                 ; Ver. 3.30. Get source line 
  1171.         mov     si,StartLine
  1172.         mov     cx,132                          ; display max 132 chars of it
  1173. @@DspLine:        
  1174.         lodsb                                   ; get a char from source
  1175.         cmp     al,20h                          ; quit on non-disp chars
  1176.         jb      @@DspDone
  1177.         mov     ah,2                            ; Dos display char.
  1178.         mov     dl,al
  1179.         int     21h
  1180.         loop    @@DspLine
  1181. @@DspDone:        
  1182. ;        push    cs                              ; Restore ds = cs
  1183. ;        pop     ds                              ; just in case...
  1184.         mov     dx, OFFSET EndStrMsg            ; CRLF
  1185.         mov     ah,9
  1186.         int     21h
  1187.         mov     ax,StartItem
  1188.         mov     bx,StartLine
  1189.         sub     ax,bx                           ; StartLoc displayable ?
  1190.         jb      @@BadErrLoc
  1191.         je      @@DsplyStart
  1192.         cmp     ax,132
  1193.         ja      @@BadErrLoc
  1194.         mov     cx,ax
  1195. @@StartLoc:
  1196.         mov     ah,2
  1197.         mov     dl,' '
  1198.         int     21h
  1199.         loop    @@StartLoc
  1200. @@DsplyStart:        
  1201.         mov     ah,2
  1202.         mov     dl,'^'
  1203.         int     21h                             ; Point at error with ^
  1204.         mov     ax,ErrLoc
  1205.         mov     cx,ax
  1206.         sub     ax, StartLine
  1207.         jbe     @@BadErrLoc
  1208.         cmp     ax,132
  1209.         ja      @@BadErrLoc
  1210.         dec     cx                              ; A slight problem here
  1211.         dec     cx                              ; with counting to end of
  1212.         sub     cx,StartItem                    ; errored item. V4.00
  1213.         jbe     @@BadErrLoc
  1214. @@ErrLoc:
  1215.         mov     ah,2
  1216.         mov     dl,'-'
  1217.         int     21h
  1218.         loop    @@ErrLoc
  1219.         mov     ah,2
  1220.         mov     dl,'^'
  1221.         int     21h                             ; Point at error with ^
  1222. @@BadErrLoc:        
  1223.         mov     dx, OFFSET EndStrMsg            ; CRLF
  1224.         mov     ah,9
  1225.         int     21h
  1226.  
  1227.         mov     dx, OFFSET LinErrMsg
  1228.         mov     ah,9
  1229.         int     21h
  1230.  
  1231.         mov     ax,LineNr
  1232.         xor     cx,cx
  1233.         call    PrintAX
  1234.         mov     dx, OFFSET InvalidMsg
  1235.         mov     ah,9
  1236.         int     21h
  1237.         mov     dx,SynErrMsg
  1238.         mov     ah,9
  1239.         int     21h
  1240.         cmp     BadNum, True
  1241.         mov     dx, OFFSET BadNumMsg
  1242.         jz      @@ExtraError
  1243.         cmp     BadRange, True
  1244.         mov     dx, OFFSET BadRangeMsg
  1245.         jz      @@ExtraError
  1246.         cmp     BadParm, True
  1247.         mov     dx, OFFSET BadParmMsg
  1248.         jz      @@ExtraError
  1249.         cmp     BadString, True
  1250.         mov     dx, OFFSET BadStringMsg
  1251.         jnz     @@ExtraDone
  1252.  
  1253. @@ExtraError:
  1254.         push    dx
  1255.         mov     dx, OFFSET ExtraErrMsg
  1256.         mov     ah,9
  1257.         int     21h
  1258.         pop     dx
  1259.         mov     ah,9
  1260.         int     21h
  1261. @@ExtraDone:
  1262.         mov     dx, OFFSET EndStrMsg
  1263.  
  1264. ErrorMessage:                   ; straight to here on "option" errors
  1265.         push    cs
  1266.         pop     ds
  1267.         mov     ah,9
  1268.         int     21h
  1269.         mov     ax,4C01h
  1270.         int 21h
  1271. Syntax Endp
  1272.  
  1273. StartToken:
  1274.         mov     StartItem, si   ; 3.30 error displaying
  1275.         push    es di
  1276.  
  1277.         push    ds
  1278.         pop     es
  1279.  
  1280.         call    GetToken        ; Return token, with orig. case if a single
  1281.         call    FindToken       ; letter, then look it up.
  1282.         pop     di es
  1283.         jnc     @@TestExtended  ; 3.30 error handling
  1284.         mov     SynErrMsg, OFFSET BadTokenMsg
  1285.         mov     ErrLoc, si
  1286.         jmp     Syntax
  1287. @@TestExtended:
  1288.         cmp     al,EXTENDED_CODE
  1289.          je     @@SaveExtended
  1290.  
  1291.         call    SaveChar
  1292.         jmp     ParseNextChar
  1293.  
  1294. @@SaveExtended:
  1295. ; **** Stuffkey V.4.00 supports extended codes {IfSucc}, {Else}, {Endif}
  1296. ;      as of 19 Oct 92, {IfSucc} is simply stuffed; {Else} and {Endif}
  1297. ;      are "double stuffed" - a temporarily crude way to mark them unique.
  1298. ;
  1299. ;        cmp    ah,IFSUCCESS_CODE
  1300. ;         je    @@Save2                 ; or wherever you want..
  1301.         cmp    ah,ELSE_CODE
  1302.          je    @@DoubleStuff            ; need to mark else & endif so
  1303.         cmp    ah,ENDIF_CODE            ; if & else can find them...
  1304.          jne   @@NotIfCode              ; crude in 4.0 - improve! JG.
  1305. @@DoubleStuff:
  1306.         stosw
  1307.         xchg    al,ah                   ; store code again, need it in al
  1308.         stosw
  1309.         xchg    al,ah                   ; put it back...just in case?
  1310.         Jmp     ParseNextChar
  1311. ; **** end Stuffkey V.4.00 additions.
  1312.         
  1313. @@NotIfCode:
  1314.         cmp     ah,ATTIME_CODE
  1315.          je     AtTime
  1316.         cmp     ah,DELTATIME_CODE
  1317.          je     DeTime
  1318.         cmp     ah,SETTIMEOUT_CODE
  1319.          je     TimeOut
  1320.         cmp     ah,FIND_CODE
  1321.          je     FindNear
  1322.         cmp     ah,PROMPT_CODE
  1323.          je     PromptNear
  1324. ;        cmp     ah,PRTSCRN_CODE
  1325. ;         je     @@Save2
  1326. ;        cmp     ah,REBOOT_CODE
  1327. ;         je     @@Save2
  1328. ;
  1329.  
  1330. @@Save2:
  1331.         stosw
  1332.         jmp     ParseNextChar
  1333.  
  1334. FindNear:
  1335.         jmp FindText
  1336.  
  1337. PromptNear:
  1338.         jmp PromptText
  1339.  
  1340. SignalReBoot:
  1341.         mov ax,EXTENDED_CODE + (REBOOT_CODE * 256)
  1342.         stosw
  1343.          jmp ParseNextChar
  1344.  
  1345. ReadFile proc near
  1346.  
  1347.         cmp byte ptr [si],':'
  1348.          jne @@Skip
  1349.         inc si
  1350. @@Skip:
  1351.         mov dx,si
  1352. @@Next:
  1353.         lodsb
  1354.         cmp al,' '
  1355.          ja @@Next
  1356.         dec si
  1357.  
  1358.         mov ax,3D00h                    ; Open file for Read_Only
  1359.         mov byte ptr [si],al            ; Make ASCIIZ filename
  1360.  
  1361.         int 21h
  1362.         mov dx, OFFSET FileErrMsg
  1363.         jc ErrorMessage
  1364.  
  1365.         mov bx,ax
  1366.         mov ah,3Fh                      ; Read File
  1367.         mov dx, OFFSET ProgramEnd
  1368.         mov si,dx
  1369.         mov cx, - (OFFSET ProgramEnd)   ; Max Size in segment
  1370.         int 21h
  1371.         mov dx, OFFSET FileErrMsg
  1372.          jc ErrorMessage
  1373.  
  1374.         add si, ax
  1375.         mov byte ptr [si],EOF
  1376.         sub si, ax                      ; Point back to start of filebuffer
  1377.  
  1378.         mov ah,3Eh
  1379.         int 21h                         ; Close this file
  1380.  
  1381.          jmp RestartParse               ; Parse file buffer!
  1382. ReadFile endp
  1383.  
  1384. SetBufferSize proc near
  1385.  
  1386.         cmp byte ptr [si],':'
  1387.          jne @@Skip
  1388.         inc si
  1389. @@Skip:
  1390.         mov bx,-( OFFSET StuffBuffer - MoveDown) + 32; Max text buffer
  1391.         call GetNumber
  1392.         add bx,OFFSET StuffBuffer - MoveDown + 15
  1393.         and bx,0FFF0h
  1394.         mov [ES:ResidentSize],bx
  1395.          jmp ParseNextChar
  1396.  
  1397. SetBufferSize endp
  1398.  
  1399. SetSemafor proc    near
  1400.         lodsw
  1401.         mov [es:Semafor_1 - MoveDown],ax
  1402.         mov [Semafor_2],ax
  1403.          jmp ParseNextChar
  1404. SetSemafor endp
  1405.  
  1406. UseExpandedBuffer proc near
  1407.         push ds
  1408.         mov ds,[BiosSeg]
  1409.  
  1410.         mov ax,[DS:KbdBufferStart]      ; Keyboard Buffer start address
  1411.         mov [ES:BufferStartAddr-2-MoveDown],ax
  1412.         mov ax,[DS:KbdBufferEnd]        ; Keyboard Buffer end address
  1413.         mov [ES:BufferEndAddr-2-MoveDown],ax
  1414.  
  1415.         pop ds
  1416.          jmp ParseNextChar
  1417. UseExpandedBuffer endp
  1418.  
  1419. ParseOption Proc near
  1420.         mov StartItem, si               ; 3.30 error hndl. Save ptr to 
  1421.         lodsb                           ; current parsing area/item
  1422.         cmp al,'a'
  1423.          jb @@Upper
  1424.         cmp al,'z'
  1425.          ja @@Upper
  1426.         sub al,'a'-'A'
  1427. @@Upper:
  1428.         cmp al,'B'
  1429.          je SetBufferSize
  1430.         cmp al,'F'
  1431.          je ReadFile
  1432.         cmp al,'L'
  1433.          je ListKeys
  1434.         cmp al,'S'
  1435.          je SetSemafor
  1436.         cmp al,'E'
  1437.          je UseExpandedBuffer
  1438.         cmp al,'R'
  1439.          je @@Remove                     ; 3.30 more error handling
  1440.         mov SynErrMsg, OFFSET BadCmdOptMsg
  1441.         mov ErrLoc, si
  1442.         jmp Syntax
  1443. @@Remove:
  1444.         call FindFirst
  1445.          jz @@TryRemove
  1446.         mov SynErrMsg, OFFSET RemNresErrMsg
  1447.         mov ErrLoc, si                 ; Setup to show error message,
  1448.         jmp Syntax                     ; First copy, nothing to remove!
  1449. @@TryRemove:
  1450.         mov ax,3508h
  1451.         int 21h
  1452.         cmp bx, OFFSET MyTimer - MoveDown
  1453.          jne @@CannotRemove
  1454.         mov ax, es
  1455.         cmp ax, dx
  1456.          jne @@CannotRemove             ; Other TSR has timer vector!
  1457.  
  1458.         mov ax,352Fh
  1459.         int 21h
  1460.         cmp bx, OFFSET Int2F - MoveDown
  1461.          jne @@CannotRemove
  1462.         mov ax, es
  1463.         cmp ax, dx
  1464.          jne @@CannotRemove             ; Other TSR has Int 2F vector!
  1465.  
  1466. ; OK to remove previous copy from RAM
  1467. ; First, restore timer vector
  1468.  
  1469.         push ds
  1470.         mov dx,[word ptr ES:OldTimer-MoveDown]
  1471.         mov ds,[word ptr ES:OldTimer+2-MoveDown]
  1472.         mov ax,2508h
  1473.         int 21h
  1474.  
  1475. ; Then, restore Int 2F vector
  1476.  
  1477.         mov dx,[word ptr ES:OldInt2F-MoveDown]
  1478.         mov ds,[word ptr ES:OldInt2F+2-MoveDown]
  1479.         mov ax,252Fh
  1480.         int 21h
  1481.  
  1482.         pop ds
  1483.  
  1484. ; Next, release the memory segment
  1485. ; ES -> to previos copy!
  1486.  
  1487.         mov ah,49h
  1488.         int 21h
  1489.  
  1490.         mov dx, OFFSET RemovedMsg
  1491.         mov ah,9
  1492.         int 21h
  1493.  
  1494.         mov ax,4C00h
  1495.         int 21h
  1496.  
  1497. @@CannotRemove:
  1498.         mov dx, OFFSET NotRemovedMsg
  1499.         mov ah,9
  1500.         int 21h
  1501.  
  1502.         mov ax,4C01h
  1503.         int 21h
  1504.  
  1505. ParseOption Endp
  1506.  
  1507. hour    dw ?
  1508. min     dw ?
  1509. sec     dw ?
  1510.  
  1511. DeTime Proc near
  1512.         mov ax,EXTENDED_CODE + (DELTATIME_CODE * 256)
  1513.         jmp short ParseTime
  1514. AtTime:
  1515.         mov ax,EXTENDED_CODE + (ATTIME_CODE * 256)
  1516.         jmp short ParseTime
  1517. TimeOut:
  1518.         mov ax,EXTENDED_CODE + (SETTIMEOUT_CODE * 256)
  1519. ParseTime:
  1520.         stosw                           ; Save marker for time
  1521.  
  1522. ; FIX BUG found by davidgb. HOUR and Min MUST be initialized to ZERO!
  1523.  
  1524.         xor ax,ax
  1525.         mov [hour],ax
  1526.         mov [min],ax
  1527.  
  1528. ; END OF bug-fix
  1529.         
  1530.         ; ** 3.30. Preset error msg as GetNumber jmps directly to        
  1531.         ; "Syntax" if it gets a bad input. Terje's 'efficient' but 
  1532.         ; hard to follow style. J.G.
  1533.         
  1534.         mov SynErrMsg, OFFSET BadTimeMsg
  1535.         mov BadNum, False
  1536.         mov BadRange, False
  1537.                                                 
  1538.         mov al,[si]                     ; si -> start of number
  1539.         cmp al,'.'                      ; decimal point?
  1540.         jne @@Normal                    ; No, go with normal time
  1541.         inc si                          ; Else, skip '.', and get number
  1542.         mov bx,18                       ; as timer ticks, max 18.
  1543.         call GetNumber                  ; Note: Getnumber will NOT return
  1544.                                         ; on a bad value or range!!
  1545.         sub dx,dx                       ; Time comes back in bx.
  1546.         mov ax,dx                       ; Pass ticks in dx:ax, with dx=0.
  1547.         or  al,bl                       ; "or" in ticks, test for unwanted
  1548.         jnz @@SomeTicks                 ; zero ticks. Default 1 tick.
  1549.         inc al
  1550. @@SomeTicks:
  1551.         jmp @@SaveTicks
  1552.  
  1553. @@Normal:
  1554.         mov bx,59                       ; Max value. Note GetNumber
  1555.         call GetNumber                  ; will NOT return if bad value!
  1556.         cmp al,':'
  1557.          jne @@SaveSec
  1558. @@Mins:
  1559.         mov [min],bx
  1560.         mov bx,59
  1561.         call GetNumber
  1562.         cmp al,':'
  1563.          jne @@SaveSec
  1564.  
  1565.         xchg bx,[min]
  1566.         mov [hour],bx
  1567.         mov bx,59
  1568.         call GetNumber
  1569.         cmp al,':'
  1570.          jne @@SaveSec
  1571. BadTime:
  1572.         mov ErrLoc, si
  1573.         jmp Syntax
  1574.  
  1575. @@SaveSec:
  1576.         mov [sec],bx
  1577.  
  1578. ; Now convert hour:min:sec into Timer ticks:
  1579. ; Ticks= (hour*TicksPrHour) + (((min*60)+sec) * 34829 + 956) DIV 1913
  1580. ; 34829 / 1913 is 18.206482, which is the closest possible result to
  1581. ; the true value of 18.206493 Ticks/second, using only 16 bit mul and div.
  1582.  
  1583.         mov ax,(TicksPrHour - 65536)
  1584.         mul [hour]
  1585.         add dx,[hour]                   ; DX:AX = hour*TicksPrHour
  1586.         push ax                         ; Save DX:AX
  1587.         push dx                         ; --- " ---
  1588.  
  1589.         mov al,60
  1590.         mul [byte ptr min]
  1591.         add ax,[sec]                    ; AX has # of seconds
  1592.  
  1593.         mov dx,34829
  1594.         mul dx
  1595.         add ax,1913 Shr 1               ; Add 1913/2 to get automatic rounding
  1596.         adc dx,0                        ; of fractional timer ticks
  1597.         mov bx,ax
  1598.         mov ax,dx
  1599.         xor dx,dx
  1600.         mov cx,1913
  1601.         div cx
  1602.         xchg ax,bx
  1603.         div cx                          ; BX:AX = Ticks in (min*60+sec)
  1604.  
  1605.         pop dx
  1606.         pop cx                          ; DX:CX = Ticks in hours
  1607.  
  1608.         add ax,cx
  1609.         adc dx,bx                       ; DX:AX = Total Ticks
  1610. @@SaveTicks:                            ; Here direct if arg given in ticks
  1611.                                         ; i.e. +2t.  
  1612.         stosw                           ; Save Low word of count
  1613.         mov al,dl
  1614.         stosb                           ; Save high byte of count
  1615.  
  1616.          jmp ParseNextChar
  1617. DeTime Endp
  1618.  
  1619. PromptText:
  1620.         mov SynErrMsg, OFFSET BadPromptMsg
  1621.         mov StartItem, si
  1622.         mov ax,EXTENDED_CODE + (PROMPT_CODE * 256)
  1623.         stosw
  1624.  
  1625. ;*** V.3.30 "Easy Prompt" - allows user to supply text only.
  1626. ;*** Prompt/find variables stored in destination buffer (ES:DI): 
  1627. ;    byte x, byte y, word slop, byte len, byte attrib
  1628. ;    note user never supplies len, and attrib is optional.
  1629.  
  1630.         mov al,[si]                     ; check for immediate " or ' 
  1631.         cmp al,'"'
  1632.         je easy_prompt
  1633.         cmp al,"'"
  1634.         jne normal_prompt
  1635.  
  1636. easy_prompt:
  1637.         push ax                         ; save " or ' in al
  1638.         sub ax,ax
  1639.         stosw                           ; zero Prompt dx, dy bytes
  1640.         mov ax,PROMPTSLOP               ; get default slop, store in
  1641.         mov bp,ax                       ; bp as "easy" flag, and in
  1642.         stosw                           ; dest buffer es:di -> word slop
  1643.         pop ax                          ; now es:di -> byte len
  1644.         mov ah, NO_ATTR                 ; default (no) char attribute
  1645.         inc si                          ; ds:si -> 1st char in string
  1646.         jmp Text2                       ; skip to text scanning
  1647.  
  1648. normal_prompt:        
  1649.         mov bx,127
  1650.         call GetNumber
  1651.         cmp al,','
  1652.          jne BadFindParm
  1653.         mov al,bl                       ; Save X value
  1654.         stosb
  1655.  
  1656.         mov bx,60                       ; 0<y<=60
  1657.         call GetNumber
  1658.         cmp al,','
  1659.          jne BadFindParm
  1660.         mov al,bl
  1661.         stosb                           ; Save Y value
  1662.  
  1663.          jmp short Text1
  1664.  
  1665. ;********** Error handler common to PromptText and FindText *******
  1666. ;*** 3.30 Trying to clean this up so I can understand it...
  1667. ;   Terje favors jumps over calls for speed/size, but it makes for
  1668. ; difficult code to read/modify (IMHO)! J.Geist 1Sep92
  1669. ;*** 4.00 Moved this error handler between proc's PrompText and FindText
  1670. ; as it is common to both - in fact code starting at "Text1:" is common
  1671. ; to both procs. Check ptr SynErrMsg to find 'caller'. It will point to
  1672. ; BadPromptMsg or BadFindMsg. JG 24Oct92.  
  1673. ;
  1674. BadFindParm:
  1675.         mov BadParm, True
  1676.         jmp short BadFind
  1677. BadFindVal:
  1678.         mov BadRange, True
  1679.         jmp short BadFind
  1680. BadFindString:
  1681.         mov BadString, True
  1682. BadFind:        
  1683.         mov ErrLoc, si
  1684.         jmp Syntax
  1685. ;******************** End common error handler **********************
  1686.  
  1687. FindText proc near
  1688.         mov SynErrMsg, OFFSET BadFindMsg
  1689.         mov StartItem, si
  1690.         mov ax,EXTENDED_CODE + (FIND_CODE * 256) ; 255 + 3 -> flag for Find Text
  1691.         stosw
  1692.         mov bx,132                      ; 0<x<=132
  1693.         call GetNumber
  1694.         cmp al,','
  1695.          jne BadFindParm                ;'BadFind..' labels common to 
  1696.         sub bl,1                        ; PromptText and FindText. v.4.00
  1697.          jb BadFindVal                  ; 
  1698.         mov cx,bx                       ; Save X value
  1699.  
  1700.         mov bx,60                       ; 0<y<=60
  1701.         call GetNumber
  1702.         cmp al,','
  1703.          jne BadFindParm
  1704.         sub bl,1
  1705.          jb BadFindParm
  1706.  
  1707.         mov al,80
  1708.         mul bl
  1709.         add ax, cx
  1710.         shl ax, 1
  1711.         stosw                           ; Save X,Y as starting offset
  1712.  
  1713. ;*** Starting at Text1:, code is shared by FindText and PromptText.
  1714. ;    Thus, should check pointer SynErrMsg if need to know which
  1715. ;    proc we 'came' from. v.4.00 
  1716. Text1:
  1717.         mov bx,(132*60)                 ; Get length to search in
  1718.         call GetNumber
  1719.         cmp al,','
  1720.          jne BadFindParm
  1721.         or bx,bx
  1722.          jz BadFindVal                  ; Count must be > 0
  1723.  
  1724.         mov ax,bx
  1725.         stosw                           ; Save buffer length
  1726.  
  1727.         mov bx,255
  1728.         cmp byte ptr [si],'"'
  1729.          je @@SkipAttr
  1730.         cmp byte ptr [si],"'"
  1731.          je @@SkipAttr
  1732.  
  1733.         call GetNumber
  1734.         cmp al,','
  1735.          jne BadFindParm
  1736.  
  1737.  
  1738. @@SkipAttr:
  1739.         sub bp,bp                       ; zap bp, flag for "easy prompt"
  1740.         mov ah,bl
  1741.         lodsb
  1742.         cmp al,'"'
  1743.          je @@1
  1744.         cmp al,"'"
  1745.          jne BadFindString
  1746. @@1:
  1747.  
  1748. ; *** V. 3.30 straight to here (Text2:) on easy_prompt.
  1749. ; ds:si -> 1st byte after " or ' in a string in source buffer
  1750. ; es:di -> to attribute byte storage in dest buffer
  1751. ; bp = PROMPTSLOP if Easy_prompt desired.
  1752. ; ah = attribute, 255 means ignore attr.
  1753. ; al = " or ' beginning the string. Result of last lodsb. (ds:si -1 )
  1754.  
  1755. Text2:                                  
  1756.         mov bx,di                       ; Save current pos for len
  1757.         stosw                           ; Store len (al) + attr (ah)
  1758.                                         ; Note len will be overwritten later
  1759.         mov ah,al                       ; save quote(s), string delimiters
  1760.         xor cx,cx
  1761. @@2:
  1762.         lodsb
  1763.         cmp al,EOF
  1764.          je  BadFindString
  1765.         cmp al,13
  1766.          je BadFindString
  1767.         cmp al,ah
  1768.          je @@3
  1769.  
  1770.         inc cx                          ; INC len
  1771.         stosb                           ; Save Text
  1772.         jmp @@2
  1773.  
  1774. @@3:
  1775. ;*** Prompt/find vars: byte x, byte y, word slop, byte len, byte attrib        
  1776.         mov [ES:bx],cl                  ; Save actual length!
  1777.         cmp bp, PROMPTSLOP              ; Are we doing an "easy prompt" ?
  1778.         jnz @@Pdone                     ; no - leave.
  1779.                                         ; yes, stuff default prompt values
  1780. @@default_prompt:
  1781.         add cl, PROMPTADD               ; add to actual string length
  1782.         or word ptr [ES:bx-4], 0        ; double check "easy prompt"
  1783.         jnz @@Pdone
  1784.         mov [ES:bx-4], cl               ; store in [cursor horizontal - x]
  1785. @@Pdone:        
  1786.         jmp ParseNextChar               ; jump (shudder) to parser
  1787. FindText endp
  1788.  
  1789. GetNumber proc near
  1790. ; input: SI -> first char to convert, BX = max value
  1791. ; Output: BX = number if no error. 
  1792. ;         Jumps directly to Syntax error handler on error (hmmm)
  1793. ;         3.30 sets BadNum, BadRange for invalid number or range.
  1794.         
  1795.         mov  BadNum, False              ; Clear bad value & range flags
  1796.         mov  BadRange, False            ;
  1797.         mov  ErrLoc, si                 ; Save source pos. in case of err.
  1798.         push cx                         ; Use as temp buffer
  1799.         push dx                         ; For mul
  1800.         push di                         ; For sign flag
  1801.  
  1802.         sub cx,cx
  1803.         mov ah,ch
  1804.         mov di,cx                       ; Zero DI -> Positive
  1805.  
  1806.         cmp byte ptr [si],'-'
  1807.          jne @@GetLoop
  1808.         dec di
  1809.         inc si
  1810.  
  1811. @@GetLoop:
  1812.         lodsb
  1813.         cmp al,' '
  1814.          jbe @@GetEnd
  1815.         cmp al,':'
  1816.          je @@GetEnd
  1817.         cmp al,','
  1818.          je @@GetEnd
  1819.  
  1820.         sub al,'0'
  1821.          jb @@BadNumber
  1822.         cmp al,9
  1823.          ja @@BadNumber
  1824.  
  1825. ; Valid decimal digit!                  ; These comments added in 3.30
  1826.         xchg ax,cx                      ; swap new#(ax) with old#(cx) 
  1827.         mov dx,10                       ; want to mul old number by 10.
  1828.         mul dx                          ; old#(ax) * 10(dx) -> ax
  1829.         add cx,ax                       ; now add in new#, keep in cx.
  1830.          jmp @@GetLoop                  ; Go check for more digits, etc.
  1831. @@GetEnd:
  1832.         cmp al,EOF
  1833.          jne @@1
  1834.         dec si                          ; Prepare to reload AL
  1835. @@1:
  1836.         cmp cx,bx                       ; Valid value?
  1837.          ja @@BadRange                 ; bad if new#(cx) > max#(bx)
  1838.         mov bx,cx                       ; 
  1839.  
  1840.         or di,di
  1841.          jz @@done
  1842.  
  1843.         neg bx                          ; return -BX
  1844.  
  1845. @@done:
  1846.         pop di
  1847.         pop dx
  1848.         pop cx
  1849.         ret
  1850. @@BadNumber:
  1851.         mov BadNum, True                ; Bad number implies bad range
  1852. @@BadRange:                             ; so chk it 1st, then range,
  1853.         mov BadRange, True              ; in error display routine. v3.30
  1854.         mov ErrLoc, si                  ; Save in ErrLoc pointer.
  1855.         jmp Syntax                      ; saves space, but ?
  1856. GetNumber endp
  1857.  
  1858. SaveChar proc near
  1859. ; AL, AH = char, scan to save in StuffBuffer
  1860.  
  1861.         or al,al
  1862.          je @@Save2
  1863.         cmp al,224
  1864.          je @@Save2
  1865.  
  1866.         cmp al,254
  1867.          jae @@Save3
  1868.         cmp ah,2                        ; Scan for normal chars
  1869.          jne @@Save3
  1870.  
  1871.         mov ah,14
  1872.         cmp al,8
  1873.          je @@Save3
  1874.         mov ah,15
  1875.         cmp al,9
  1876.          je @@Save3
  1877.         mov ah,28
  1878.         cmp al,13
  1879.          je @@Save3
  1880.         mov ah,1
  1881.         cmp al,27
  1882.          je @@Save3
  1883.  
  1884. ; Normal character, store just the char itself
  1885.  
  1886.         stosb
  1887.         ret
  1888.  
  1889. @@Save2:
  1890.         stosw
  1891.         ret
  1892.  
  1893. @@Save3:
  1894.         mov byte ptr [es:di],254
  1895.         inc di
  1896.         stosw
  1897.         ret
  1898. SaveChar endp
  1899.  
  1900. MaxTokenSize = 8                        ; V.4.0. 9 vs 8 for {IfSuccess}
  1901.                                         ; leaving as {IfSucc} for now.
  1902.  
  1903. CurToken   db MaxTokenSize dup (0)
  1904.  
  1905. TokenTable      label byte
  1906.  
  1907. T_S     struc
  1908. tname   db      MaxTokenSize dup (0)
  1909. tchr    db      ?
  1910. tscn    db      ?
  1911.         ends
  1912.  
  1913.         T_S     <"ESC",27,1>
  1914.  
  1915. TokenRecSize    = $ - offset TokenTable
  1916.  
  1917.         T_S     <"aEsc",0,1>
  1918.  
  1919.         T_S     <"^@",0,3>
  1920.         T_S     <"^A",1,30>
  1921.         T_S     <"^B",2,48>
  1922.         T_S     <"^C",3,46>
  1923.         T_S     <"^D",4,32>
  1924.         T_S     <"^E",5,18>
  1925.         T_S     <"^F",6,33>
  1926.         T_S     <"^G",7,34>
  1927.         T_S     <"^H",8,35>
  1928.         T_S     <"^I",9,23>
  1929.         T_S     <"^J",10,36>
  1930.         T_S     <"^K",11,37>
  1931.         T_S     <"^L",12,38>
  1932.         T_S     <"^M",13,50>
  1933.         T_S     <"^N",14,49>
  1934.         T_S     <"^O",15,24>
  1935.         T_S     <"^P",16,25>
  1936.         T_S     <"^Q",17,16>
  1937.         T_S     <"^R",18,19>
  1938.         T_S     <"^S",19,31>
  1939.         T_S     <"^T",20,20>
  1940.         T_S     <"^U",21,22>
  1941.         T_S     <"^V",22,47>
  1942.         T_S     <"^W",23,17>
  1943.         T_S     <"^X",24,45>
  1944.         T_S     <"^Y",25,21>
  1945.         T_S     <"^Z",26,44>
  1946.         T_S     <"^[",27,26>
  1947.         T_S     <"^\",28,43>
  1948.         T_S     <"^]",29,27>
  1949.         T_S     <"^^",30,7>
  1950.         T_S     <"^_",31,12>
  1951.  
  1952.         T_S     <"NUL",0,3>
  1953.         T_S     <"SOH",1,30>
  1954.         T_S     <"STX",2,48>
  1955.         T_S     <"ETX",3,46>
  1956.         T_S     <"EOT",4,32>
  1957.         T_S     <"ENQ",5,18>
  1958.         T_S     <"ACK",6,33>
  1959.         T_S     <"BEL",7,34>
  1960. ;        T_S     <"BS",8,35>            ; Defined as BS key
  1961.         T_S     <"HT",9,23>             ; HT = ^H = TAB
  1962.         T_S     <"LF",10,36>
  1963.         T_S     <"VT",11,37>
  1964.         T_S     <"FF",12,38>
  1965. ;        T_S     <"CR",13,50>           ;  --"--     CR
  1966.         T_S     <"SO",14,49>
  1967.         T_S     <"SI",15,24>
  1968.         T_S     <"DLE",16,25>
  1969.         T_S     <"DC1",17,16>
  1970.         T_S     <"DC2",18,19>
  1971.         T_S     <"DC3",19,31>
  1972.         T_S     <"DC4",20,20>
  1973.         T_S     <"NAK",21,22>
  1974.         T_S     <"SYN",22,47>
  1975.         T_S     <"ETB",23,17>
  1976.         T_S     <"CAN",24,45>
  1977.         T_S     <"EM",25,21>
  1978.         T_S     <"SUB",26,44>
  1979. ;        T_S     <"ESC",27,26>          ;  --"--     ESC
  1980.         T_S     <"FS",28,43>
  1981.         T_S     <"GS",29,27>
  1982.         T_S     <"RS",30,7>
  1983.         T_S     <"US",31,12>
  1984.  
  1985. FirstChar       label byte              ; Use to translate characters into
  1986.                                         ; char:scan pairs
  1987.  
  1988.         T_S     <" ",32,57>
  1989.         T_S     <"!",33,2>
  1990.         T_S     <'"',34,40>
  1991.         T_S     <"#",35,4>
  1992.         T_S     <"$",36,5>
  1993.         T_S     <"%",37,6>
  1994.         T_S     <"&",38,8>
  1995.         T_S     <"'",39,40>
  1996.         T_S     <"(",40,10>
  1997.         T_S     <")",41,11>
  1998.         T_S     <"*",42,9>
  1999.         T_S     <"+",43,13>
  2000.         T_S     <",",44,51>
  2001.         T_S     <"-",45,12>
  2002.         T_S     <".",46,52>
  2003.         T_S     <"/",47,53>
  2004.  
  2005.         T_S     <"0",48,11>
  2006.         T_S     <"1",49,2>
  2007.         T_S     <"2",50,3>
  2008.         T_S     <"3",51,4>
  2009.         T_S     <"4",52,5>
  2010.         T_S     <"5",53,6>
  2011.         T_S     <"6",54,7>
  2012.         T_S     <"7",55,8>
  2013.         T_S     <"8",56,9>
  2014.         T_S     <"9",57,10>
  2015.         T_S     <":",58,39>
  2016.         T_S     <";",59,39>
  2017.         T_S     <"<",60,51>
  2018.         T_S     <"=",61,13>
  2019.         T_S     <">",62,52>
  2020.         T_S     <"?",63,53>
  2021.  
  2022.         T_S     <"@",'@',3>
  2023.         T_S     <"A",'A',30>
  2024.         T_S     <"B",'B',48>
  2025.         T_S     <"C",'C',46>
  2026.         T_S     <"D",'D',32>
  2027.         T_S     <"E",'E',18>
  2028.         T_S     <"F",'F',33>
  2029.         T_S     <"G",'G',34>
  2030.         T_S     <"H",'H',35>
  2031.         T_S     <"I",'I',23>
  2032.         T_S     <"J",'J',36>
  2033.         T_S     <"K",'K',37>
  2034.         T_S     <"L",'L',38>
  2035.         T_S     <"M",'M',50>
  2036.         T_S     <"N",'N',49>
  2037.         T_S     <"O",'O',24>
  2038.         T_S     <"P",'P',25>
  2039.         T_S     <"Q",'Q',16>
  2040.         T_S     <"R",'R',19>
  2041.         T_S     <"S",'S',31>
  2042.         T_S     <"T",'T',20>
  2043.         T_S     <"U",'U',22>
  2044.         T_S     <"V",'V',47>
  2045.         T_S     <"W",'W',17>
  2046.         T_S     <"X",'X',45>
  2047.         T_S     <"Y",'Y',21>
  2048.         T_S     <"Z",'Z',44>
  2049.         T_S     <"[",'[',26>
  2050.         T_S     <"\",'\',43>
  2051.         T_S     <"]",']',27>
  2052.         T_S     <"^",'^',7>
  2053.         T_S     <"_",'_',12>
  2054.  
  2055.         T_S     <"`",'`',41>
  2056.         T_S     <"a",'a',30>
  2057.         T_S     <"b",'b',48>
  2058.         T_S     <"c",'c',46>
  2059.         T_S     <"d",'d',32>
  2060.         T_S     <"e",'e',18>
  2061.         T_S     <"f",'f',33>
  2062.         T_S     <"g",'g',34>
  2063.         T_S     <"h",'h',35>
  2064.         T_S     <"i",'i',23>
  2065.         T_S     <"j",'j',36>
  2066.         T_S     <"k",'k',37>
  2067.         T_S     <"l",'l',38>
  2068.         T_S     <"m",'m',50>
  2069.         T_S     <"n",'n',49>
  2070.         T_S     <"o",'o',24>
  2071.         T_S     <"p",'p',25>
  2072.         T_S     <"q",'q',16>
  2073.         T_S     <"r",'r',19>
  2074.         T_S     <"s",'s',31>
  2075.         T_S     <"t",'t',20>
  2076.         T_S     <"u",'u',22>
  2077.         T_S     <"v",'v',47>
  2078.         T_S     <"w",'w',17>
  2079.         T_S     <"x",'x',45>
  2080.         T_S     <"y",'y',21>
  2081.         T_S     <"z",'z',44>
  2082.         T_S     <"{",'{',26>
  2083.         T_S     <"|",'|',43>
  2084.         T_S     <"}",'}',27>
  2085.         T_S     <"~",'~',7>
  2086.  
  2087.         T_S     <"æ",'æ',40>
  2088.         T_S     <"¢",'¢',39>
  2089.         T_S     <"å",'å',26>
  2090.         T_S     <"Æ",'Æ',40>
  2091.         T_S     <"¥",'¥',39>
  2092.         T_S     <"Å",'Å',26>
  2093.  
  2094. LastChar        label byte
  2095.  
  2096.         T_S     <"a1",0,120>
  2097.         T_S     <"a2",0,121>
  2098.         T_S     <"a3",0,122>
  2099.         T_S     <"a4",0,123>
  2100.         T_S     <"a5",0,124>
  2101.         T_S     <"a6",0,125>
  2102.         T_S     <"a7",0,126>
  2103.         T_S     <"a8",0,127>
  2104.         T_S     <"a9",0,128>
  2105.         T_S     <"a0",0,129>
  2106.         T_S     <"a-",0,130>
  2107.         T_S     <"a=",0,131>
  2108.  
  2109.         T_S     <"BS",8,14>
  2110.         T_S     <"aBS",0,14>
  2111.         T_S     <"^BS",127,14>
  2112.  
  2113.         T_S     <"Tab",9,15>
  2114.         T_S     <"sTab",0,15>
  2115.         T_S     <"^Tab",0,148>
  2116.  
  2117.         T_S     <"CR",13,28>
  2118.         T_S     <"^CR",10,28>
  2119.         T_S     <"aCR",0,28>
  2120.  
  2121.         T_S     <"aQ",0,16>
  2122.         T_S     <"aW",0,17>
  2123.         T_S     <"aE",0,18>
  2124.         T_S     <"aR",0,19>
  2125.         T_S     <"aT",0,20>
  2126.         T_S     <"aY",0,21>
  2127.         T_S     <"aU",0,22>
  2128.         T_S     <"aI",0,23>
  2129.         T_S     <"aO",0,24>
  2130.         T_S     <"aP",0,25>
  2131.         T_S     <"a[",0,26>
  2132.         T_S     <"a]",0,27>
  2133.  
  2134.         T_S     <"aA",0,30>
  2135.         T_S     <"aS",0,31>
  2136.         T_S     <"aD",0,32>
  2137.         T_S     <"aF",0,33>
  2138.         T_S     <"aG",0,34>
  2139.         T_S     <"aH",0,35>
  2140.         T_S     <"aJ",0,36>
  2141.         T_S     <"aK",0,37>
  2142.         T_S     <"aL",0,38>
  2143.         T_S     <"a;",0,39>
  2144.         T_S     <"a'",0,40>
  2145.         T_S     <"a`",0,41>
  2146.  
  2147.         T_S     <"a\",0,43>
  2148.         T_S     <"aZ",0,44>
  2149.         T_S     <"aX",0,45>
  2150.         T_S     <"aC",0,46>
  2151.         T_S     <"aV",0,47>
  2152.         T_S     <"aB",0,48>
  2153.         T_S     <"aN",0,49>
  2154.         T_S     <"aM",0,50>
  2155.         T_S     <"a,",0,51>
  2156.         T_S     <"a.",0,52>
  2157.         T_S     <"a/",0,53>
  2158.  
  2159.         T_S     <"a*",0,55>
  2160.  
  2161.         T_S     <"F1",0,59>
  2162.         T_S     <"F2",0,60>
  2163.         T_S     <"F3",0,61>
  2164.         T_S     <"F4",0,62>
  2165.         T_S     <"F5",0,63>
  2166.         T_S     <"F6",0,64>
  2167.         T_S     <"F7",0,65>
  2168.         T_S     <"F8",0,66>
  2169.         T_S     <"F9",0,67>
  2170.         T_S     <"F10",0,68>
  2171.  
  2172.         T_S     <"n/",'/',224>
  2173.         T_S     <"n*",'*',55>
  2174.         T_S     <"n7",'7',74>
  2175.         T_S     <"n8",'8',72>
  2176.         T_S     <"n9",'9',73>
  2177.         T_S     <"n-",'-',74>
  2178.         T_S     <"n4",'4',75>
  2179.         T_S     <"n5",'5',76>
  2180.         T_S     <"n6",'6',77>
  2181.         T_S     <"n+",'+',78>
  2182.         T_S     <"n1",'1',79>
  2183.         T_S     <"n2",'2',80>
  2184.         T_S     <"n3",'3',81>
  2185.         T_S     <"n0",'0',82>
  2186.         T_S     <"n.",'.',83>
  2187.         T_S     <"Enter",13,224>
  2188.  
  2189.         T_S     <"Home",0,71>
  2190.         T_S     <"Up"  ,0,72>
  2191.         T_S     <"PgUp",0,73>
  2192.         T_S     <"Left",0,75>
  2193.         T_S     <"Right",0,77>
  2194.         T_S     <"End" ,0,79>
  2195.         T_S     <"Down",0,80>
  2196.         T_S     <"PgDn",0,81>
  2197.         T_S     <"Ins" ,0,82>
  2198.         T_S     <"Del" ,0,83>
  2199.  
  2200.         T_S     <"^n/",0,149>
  2201.         T_S     <"^n*",0,150>
  2202.         T_S     <"^Home",0,119>
  2203.         T_S     <"^Up"  ,0,141>
  2204.         T_S     <"^PgUp",0,132>
  2205.         T_S     <"^n-",0,142>
  2206.         T_S     <"^Left",0,115>
  2207.         T_S     <"^n5",0,143>
  2208.         T_S     <"^Right",0,116>
  2209.         T_S     <"^n+",0,144>
  2210.         T_S     <"^End" ,0,117>
  2211.         T_S     <"^Down",0,145>
  2212.         T_S     <"^PgDn",0,118>
  2213.         T_S     <"^Ins" ,0,146>
  2214.         T_S     <"^Del" ,0,147>
  2215.         T_S     <"^Enter",10,224>
  2216.  
  2217.         T_S     <"an/",0,164>
  2218.         T_S     <"an*",0,55>
  2219.         T_S     <"an-",0,74>
  2220.         T_S     <"an+",0,78>
  2221.         T_S     <"aEnter",10,224>
  2222.  
  2223.         T_S     <"eHome",224,71>
  2224.         T_S     <"eUp"  ,224,72>
  2225.         T_S     <"ePgUp",224,73>
  2226.         T_S     <"eLeft",224,75>
  2227.         T_S     <"eRight",224,77>
  2228.         T_S     <"eEnd" ,224,79>
  2229.         T_S     <"eDown",224,80>
  2230.         T_S     <"ePgDn",224,81>
  2231.         T_S     <"eIns" ,224,82>
  2232.         T_S     <"eDel" ,224,83>
  2233.  
  2234.         T_S     <"^eHome",224,119>
  2235.         T_S     <"^eUp"  ,224,141>
  2236.         T_S     <"^ePgUp",224,132>
  2237.         T_S     <"^eLeft",224,115>
  2238.         T_S     <"^eRight",224,116>
  2239.         T_S     <"^eEnd" ,224,117>
  2240.         T_S     <"^eDown",224,145>
  2241.         T_S     <"^ePgDn",224,118>
  2242.         T_S     <"^eIns" ,224,146>
  2243.         T_S     <"^eDel" ,224,147>
  2244.  
  2245.         T_S     <"aeHome",0,151>
  2246.         T_S     <"aeUp"  ,0,152>
  2247.         T_S     <"aePgUp",0,153>
  2248.         T_S     <"aeLeft",0,155>
  2249.         T_S     <"aeRight",0,157>
  2250.         T_S     <"aeEnd" ,0,159>
  2251.         T_S     <"aeDown",0,160>
  2252.         T_S     <"aePgDn",0,161>
  2253.         T_S     <"aeIns" ,0,162>
  2254.         T_S     <"aeDel" ,0,163>
  2255.  
  2256.         T_S     <"sF1",0,84>
  2257.         T_S     <"sF2",0,85>
  2258.         T_S     <"sF3",0,86>
  2259.         T_S     <"sF4",0,87>
  2260.         T_S     <"sF5",0,88>
  2261.         T_S     <"sF6",0,89>
  2262.         T_S     <"sF7",0,90>
  2263.         T_S     <"sF8",0,91>
  2264.         T_S     <"sF9",0,92>
  2265.         T_S     <"sF10",0,93>
  2266.  
  2267.         T_S     <"^F1",0,94>
  2268.         T_S     <"^F2",0,95>
  2269.         T_S     <"^F3",0,96>
  2270.         T_S     <"^F4",0,97>
  2271.         T_S     <"^F5",0,98>
  2272.         T_S     <"^F6",0,99>
  2273.         T_S     <"^F7",0,100>
  2274.         T_S     <"^F8",0,101>
  2275.         T_S     <"^F9",0,102>
  2276.         T_S     <"^F10",0,103>
  2277.  
  2278.         T_S     <"aF1",0,104>
  2279.         T_S     <"aF2",0,105>
  2280.         T_S     <"aF3",0,106>
  2281.         T_S     <"aF4",0,107>
  2282.         T_S     <"aF5",0,108>
  2283.         T_S     <"aF6",0,109>
  2284.         T_S     <"aF7",0,110>
  2285.         T_S     <"aF8",0,111>
  2286.         T_S     <"aF9",0,112>
  2287.         T_S     <"aF10",0,113>
  2288.  
  2289.         T_S     <"^PrtScrn",0,114>
  2290.  
  2291.         T_S     <"F11",0,133>
  2292.         T_S     <"F12",0,134>
  2293.         T_S     <"sF11",0,135>
  2294.         T_S     <"sF12",0,136>
  2295.         T_S     <"^F11",0,137>
  2296.         T_S     <"^F12",0,138>
  2297.         T_S     <"aF11",0,139>
  2298.         T_S     <"aF12",0,140>
  2299.  
  2300. ; Special functions with full names:
  2301.  
  2302.         T_S     <"PrtScrn",255,PRTSCRN_CODE>
  2303.         T_S     <"Boot"   ,255,REBOOT_CODE>
  2304.         T_S     <"^aDel"  ,255,REBOOT_CODE>     ; Ctrl-Alt-Del is an alias
  2305.                                                 ; for Boot!
  2306.         T_S     <"AtTime" ,255,ATTIME_CODE>
  2307.         T_S     <"Wait"   ,255,DELTATIME_CODE>
  2308.         T_S     <"Find"   ,255,FIND_CODE>
  2309.         T_S     <"Prompt" ,255,PROMPT_CODE>
  2310.         T_S     <"^Break" ,255,BREAK_CODE>
  2311.         T_S     <"TimeOut",255,SETTIMEOUT_CODE> ; V.3.30 for Prompt, Find
  2312.         T_S     <"IfSucc" ,255,IFSUCCESS_CODE>  ; V.4.00 test of above        
  2313.         T_S     <"IfTrue" ,255,IFSUCCESS_CODE>  ; allow If Succ, True,        
  2314.         T_S     <"IfT"    ,255,IFSUCCESS_CODE>  ; and T.        
  2315.         T_S     <"IfFail" ,255,IFFAIL_CODE>     ;                
  2316.         T_S     <"IfFalse",255,IFFAIL_CODE>     ;                
  2317.         T_S     <"IfF"    ,255,IFFAIL_CODE>     ;                
  2318.         T_S     <"Else"   ,255,ELSE_CODE>       ; " else for IfSuccess
  2319.         T_S     <"Endif"  ,255,ENDIF_CODE>      ; " end IfSuccess & Else
  2320.         T_S     <"Stop"   ,255,STOP_CODE>       ; For aborting script
  2321. EndToken        label byte
  2322.  
  2323. GetToken        proc                    ; AL = '{', SI -> next char
  2324.  
  2325.         push    cx di
  2326.  
  2327.         mov     ah,'}'                  ; Assume '{ for start of token
  2328.         cmp     al,'{'
  2329.          je     @@l1
  2330.         mov     ah,']'                  ; No, so it must be '['
  2331. @@l1:
  2332.         mov     di, offset CurToken
  2333.         mov     cx, MaxTokenSize
  2334.         lodsb                           ; Must be at least one char,
  2335. @@next:                                 ; so {{} is OK!
  2336.         stosb
  2337.         dec     cx
  2338.          jz     @@full
  2339.         lodsb
  2340.         cmp     al,' '
  2341.          jbe    @@MissingBrace
  2342.         cmp     al,ah
  2343.          jne    @@next
  2344.  
  2345.         mov     al,0
  2346.         rep     stosb
  2347. @@full:
  2348.  
  2349.         cmp     CurToken[1],0           ; Length = 1?
  2350.          je     @@done                  ; Yes, so leave alone!
  2351.  
  2352.         mov     di, offset CurToken
  2353.         mov     cx, MaxTokenSize
  2354. @@load:
  2355.         mov     al,[di]
  2356.         cmp     al,'a'
  2357.          jb     @@upper
  2358.         cmp     al,'z'
  2359.          ja     @@upper
  2360.         sub     al,'a'-'A'
  2361.         mov     [di],al
  2362. @@upper:
  2363.         inc     di
  2364.          loop   @@load
  2365. @@done:
  2366.         pop     di cx
  2367.         ret
  2368.  
  2369. @@MissingBrace:
  2370.         jmp     Syntax
  2371. GetToken        endp
  2372.  
  2373. TokenUpper      db 0
  2374.  
  2375. FindToken proc near             ; bx => token
  2376. ; Return CLC (and AX) if found, STC if not found
  2377.  
  2378.         push    cx dx si di
  2379.  
  2380.         cmp     [TokenUpper],0
  2381.          jne    @@TokenUpper
  2382.         call    UpcaseToken             ; Converts token table to uppercase!
  2383.         mov     [TokenUpper],1
  2384.  
  2385. @@TokenUpper:
  2386.         mov     dx, offset TokenTable - TokenRecSize
  2387.  
  2388. @@testtoken:
  2389.         add     dx, TokenRecSize
  2390.         cmp     dx, offset EndToken
  2391.         cmc
  2392.          jc     @@done
  2393.  
  2394.         mov     si, offset CurToken
  2395.         mov     di,dx
  2396.         mov     cx, MaxTokenSize SHR 1
  2397.    repe cmpsw
  2398.          jne     @@TestToken
  2399.  
  2400.         mov     ax,[di]
  2401.         clc
  2402. @@done:
  2403.         pop     di si dx cx
  2404.         ret
  2405. FindToken       endp
  2406.  
  2407. UpcaseToken     proc
  2408.         push    cx dx di
  2409.  
  2410.         mov     dx, offset TokenTable
  2411.  
  2412. @@testtoken:
  2413.         mov     di,dx
  2414.         cmp     byte ptr [di+1],0       ; Token length = 1?
  2415.          je     @@end                   ; Yes, so skip this!
  2416.  
  2417.         mov     cx, MaxTokenSize
  2418.  
  2419. @@upcase:
  2420.         mov     al,[di]
  2421.         or      al,al
  2422.          jz     @@end
  2423.         cmp     al,'a'
  2424.          jb     @@upper
  2425.         cmp     al,'z'
  2426.          ja     @@upper
  2427.         sub     al,'a'-'A'
  2428. @@upper:
  2429.         stosb
  2430.          loop   @@upcase
  2431. @@end:
  2432.         add     dx, TokenRecSize
  2433.         cmp     dx, offset EndToken
  2434.          jb     @@testtoken
  2435.  
  2436. @@done:
  2437.         pop     di dx cx
  2438.         ret
  2439. UpcaseToken     endp
  2440.  
  2441. ListKeys        proc    near
  2442.         push    bx cx dx si di
  2443.  
  2444.         mov     si, offset TokenTable
  2445.  
  2446. @@print3:
  2447.         mov     di, 3
  2448.  
  2449. @@testtoken:
  2450.         cmp     si, offset EndToken
  2451.          jae    @@done
  2452.  
  2453.         mov     bx,'[' + ']' * 256
  2454.         cmp     byte ptr [si],'{'
  2455.          je     @@UseBrackets
  2456.         cmp     byte ptr [si],'}'
  2457.          je     @@UseBrackets
  2458.  
  2459.         mov     bx,'{' + '}' * 256      ; Use '{}' pair for all others
  2460.  
  2461. @@UseBrackets:
  2462.         mov     dl,bl
  2463.         mov     ah,2
  2464.         int     21h
  2465.  
  2466.         mov     cx, MaxTokenSize
  2467. @@nextchar:
  2468.         mov     al,[si]
  2469.         or      al,al
  2470.          jz     @@zero
  2471.         inc     si
  2472.         mov     dl,al
  2473.         mov     ah,2
  2474.         int     21h
  2475.          loop   @@nextchar
  2476. @@zero:
  2477.         mov     dl,bh
  2478.         mov     ah,2
  2479.         int     21h
  2480.  
  2481.         add     si,cx
  2482.         call    Space
  2483.  
  2484.         lodsb                   ; Character value
  2485.         xor     ah,ah
  2486.         mov     cx,3
  2487.         call    PrintAX
  2488.         mov     dl,':'
  2489.         mov     ah,2
  2490.         int     21h
  2491.         lodsb                   ; Character value
  2492.         xor     ah,ah
  2493.         xor     cx,cx
  2494.         call    PrintAX
  2495.         dec     di
  2496.          jz     @@Eoln
  2497.  
  2498.         add     cx,8
  2499.         call    Space
  2500.          jmp    @@testtoken
  2501. @@Eoln:
  2502.         mov     dx, offset CRLF
  2503.         mov     ah,9
  2504.         int     21h
  2505.          jmp    @@print3
  2506. @@done:
  2507.         pop     di si dx cx bx
  2508.  
  2509.         mov     ax,4C00h
  2510.         int     21h
  2511.  
  2512.         ret
  2513. ListKeys        endp
  2514.  
  2515. PrintAX proc    near
  2516.         push    dx si di
  2517.  
  2518.         mov     si,ax
  2519.         mov     bx,10
  2520.         mov     di,cx
  2521.         xor     cx,cx
  2522. @@next:
  2523.         mov     ax,si
  2524.         xor     dx,dx
  2525.         div     bx
  2526.         mov     si,ax
  2527.         mov     ah,2
  2528.         add     dl,'0'
  2529.         push    dx
  2530.         inc     cx
  2531.         or      si,si
  2532.          jnz    @@next
  2533.  
  2534.         sub     di,cx
  2535.          jbe    @@popDL
  2536.  
  2537.         xchg    cx,di
  2538.         call    Space
  2539.         xchg    cx,di
  2540. @@popDL:
  2541.         pop     dx
  2542.         mov     ah,2
  2543.         int     21h
  2544.          loop   @@popDL
  2545.  
  2546.         mov     cx,di
  2547.         pop     di si dx
  2548.         ret
  2549. PrintAX endp
  2550.  
  2551. Space   proc
  2552.  
  2553.          jcxz   @@done
  2554. @@space:
  2555.         mov     dl,' '
  2556.         mov     ah,2
  2557.         int     21h
  2558.          loop   @@space
  2559. @@done:
  2560.         ret
  2561.  
  2562. Space   endp
  2563.  
  2564. ProgramEnd label byte
  2565.  
  2566. CODE ENDS
  2567.         END start
  2568.  
  2569.